From 9d41c890cf3eeef4985fe2134350a68513b9e51f Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 26 Nov 2013 17:16:38 +0100 Subject: [PATCH 001/439] Starting work on LDAP --- coreapi/contactprovider.c | 37 ++++++++++++++++++++++ coreapi/contactprovider.h | 26 +++++++++++++++ coreapi/linphonecore.h | 66 ++++++++++++++++++++++----------------- 3 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 coreapi/contactprovider.c create mode 100644 coreapi/contactprovider.h diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c new file mode 100644 index 000000000..d8e7cb7ee --- /dev/null +++ b/coreapi/contactprovider.c @@ -0,0 +1,37 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "contactprovider.h" + +struct linphone_contact_provider { + belle_sip_object_t base; +}; + +linphone_contact_provider_t* linphone_contact_provider_create() +{ + linphone_contact_provider_t* obj = belle_sip_object_new(linphone_contact_provider_t); + return obj; +} + +static void linphone_contact_provider_destroy() +{ + +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(linphone_contact_provider_t); +BELLE_SIP_INSTANCIATE_VPTR(linphone_contact_provider_t, belle_sip_object_t, + linphone_contact_provider_destroy, NULL, NULL,FALSE); + diff --git a/coreapi/contactprovider.h b/coreapi/contactprovider.h new file mode 100644 index 000000000..b1a502b21 --- /dev/null +++ b/coreapi/contactprovider.h @@ -0,0 +1,26 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include "linphonecore.h" + + +typedef struct linphone_contact_provider linphone_contact_provider_t; +#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,linphone_contact_provider_t) + + + +linphone_contact_provider_t* linphone_contact_provider_create(); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 317f01875..d8a0e26db 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -32,6 +32,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" +#include + #define LINPHONE_IPADDR_SIZE 64 #define LINPHONE_HOSTNAME_SIZE 128 @@ -402,7 +404,7 @@ typedef enum _LinphonePrivacy { * **/ LinphonePrivacyCritical=0x10, - + /** * Special keyword to use privacy as defined either globally or by proxy using linphone_proxy_config_set_privacy() */ @@ -442,7 +444,7 @@ LINPHONE_PUBLIC LinphoneInfoMessage *linphone_info_message_copy(const LinphoneIn * @ingroup media_parameters **/ struct _LinphoneVideoPolicy{ - bool_t automatically_initiate; /** Can be created by linphone_chat_room_create_message(). */ typedef struct _LinphoneChatMessage LinphoneChatMessage; - + /** * A chat room is the place where text messages are exchanged. *
Can be created by linphone_core_create_chat_room(). @@ -943,7 +945,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 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); @@ -1021,23 +1023,23 @@ typedef void (*LinphoneCoreCallEncryptionChangedCb)(LinphoneCore *lc, LinphoneCa * Registration state notification callback prototype * */ typedef void (*LinphoneCoreRegistrationStateChangedCb)(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); -/** Callback prototype - * @deprecated +/** Callback prototype + * @deprecated */ typedef void (*ShowInterfaceCb)(LinphoneCore *lc); -/** Callback prototype - * @deprecated +/** Callback prototype + * @deprecated */ typedef void (*DisplayStatusCb)(LinphoneCore *lc, const char *message); -/** Callback prototype - * @deprecated +/** Callback prototype + * @deprecated */ typedef void (*DisplayMessageCb)(LinphoneCore *lc, const char *message); -/** Callback prototype - * @deprecated +/** Callback prototype + * @deprecated */ typedef void (*DisplayUrlCb)(LinphoneCore *lc, const char *message, const char *url); -/** Callback prototype +/** Callback prototype */ typedef void (*LinphoneCoreCbFunc)(LinphoneCore *lc,void * user_data); /** @@ -1055,7 +1057,7 @@ typedef void (*LinphoneCoreNotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneF * Callback prototype */ typedef void (*LinphoneCoreNewSubscriptionRequestedCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -/** +/** * Callback for requesting authentication information to application or user. * @param lc the LinphoneCore * @param realm the realm (domain) on which authentication is required. @@ -1064,7 +1066,7 @@ typedef void (*LinphoneCoreNewSubscriptionRequestedCb)(LinphoneCore *lc, Linphon */ typedef void (*LinphoneCoreAuthInfoRequestedCb)(LinphoneCore *lc, const char *realm, const char *username, const char *domain); -/** +/** * Callback to notify a new call-log entry has been added. * This is done typically when a call terminates. * @param lc the LinphoneCore @@ -1091,8 +1093,8 @@ typedef void (*LinphoneCoreTextMessageReceivedCb)(LinphoneCore *lc, LinphoneChat * @param LinphoneChatMessage incoming message */ typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); - -/** + +/** * Callback for being notified of DTMFs received. * @param lc the linphone core * @param call the call that received the dtmf @@ -1112,7 +1114,7 @@ typedef void (*LinphoneCoreBuddyInfoUpdatedCb)(LinphoneCore *lc, LinphoneFriend */ typedef void (*LinphoneCoreTransferStateChangedCb)(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); -/** +/** * Callback for receiving quality statistics for calls. * @param lc the LinphoneCore * @param call the call @@ -1120,11 +1122,11 @@ typedef void (*LinphoneCoreTransferStateChangedCb)(LinphoneCore *lc, LinphoneCal */ typedef void (*LinphoneCoreCallStatsUpdatedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); -/** +/** * Callback prototype for receiving info messages. * @param lc the LinphoneCore * @param call the call whose info message belongs to. - * @param msg the info message. + * @param msg the info message. */ typedef void (*LinphoneCoreInfoReceivedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); @@ -1411,7 +1413,7 @@ LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadT * @param rate can be #LINPHONE_FIND_PAYLOAD_IGNORE_RATE * @param channels number of channels, can be #LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS * @return Returns NULL if not found. - */ + */ LINPHONE_PUBLIC PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); @@ -1427,7 +1429,7 @@ LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore * * @ingroup proxy */ LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); - + LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc); @@ -1584,28 +1586,28 @@ LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *l * @ingroup network_parameters * Return the availability of uPnP. * - * @return true if uPnP is available otherwise return false. + * @return true if uPnP is available otherwise return false. */ bool_t linphone_core_upnp_available(); /** * @ingroup network_parameters - * Return the internal state of uPnP. + * Return the internal state of uPnP. * * @param lc #LinphoneCore - * @return an LinphoneUpnpState. + * @return an LinphoneUpnpState. */ LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); /** * @ingroup network_parameters - * Return the external ip address of router. + * Return the external ip address of router. * In some cases the uPnP can have an external ip address but not a usable uPnP - * (state different of Ok). + * (state different of Ok). * * @param lc #LinphoneCore * @return a null terminated string containing the external ip address. If the - * the external ip address is not available return null. + * the external ip address is not available return null. */ const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc); @@ -2147,6 +2149,14 @@ LINPHONE_PUBLIC const char *linphone_core_get_video_display_filter(LinphoneCore LINPHONE_PUBLIC void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filtername); +/** Contact Providers + */ +BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) +BELLE_SIP_TYPE_ID(linphone_contact_provider_t) +BELLE_SIP_DECLARE_TYPES_END + +BELLE_SIP_DECLARE_VPTR(linphone_contact_provider_t) + #ifdef __cplusplus } #endif From 006ba8be2e0b8a22849f0f1130965b7387e8e7eb Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 28 Nov 2013 11:00:26 +0100 Subject: [PATCH 002/439] Progress commit: basic object structure is here --- configure.ac | 19 +++ coreapi/Makefile.am | 8 +- coreapi/contactprovider.c | 94 ++++++++++-- coreapi/contactprovider.h | 46 +++++- coreapi/ldap/ldapprovider.c | 290 ++++++++++++++++++++++++++++++++++++ coreapi/ldap/ldapprovider.h | 42 ++++++ coreapi/linphonecore.h | 6 +- 7 files changed, 483 insertions(+), 22 deletions(-) create mode 100644 coreapi/ldap/ldapprovider.c create mode 100644 coreapi/ldap/ldapprovider.h diff --git a/configure.ac b/configure.ac index b1a4df656..e7256e06b 100644 --- a/configure.ac +++ b/configure.ac @@ -161,6 +161,24 @@ AC_ARG_ENABLE(x11, [enable_x11=true] ) +dnl conditional build of LDAP support +AC_ARG_ENABLE(ldap, + [AS_HELP_STRING([--disable-ldap], [Disable LDAP support (default=no)])], + [case "${enableval}" in + yes) enable_ldap=true ;; + no) enable_ldap=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-ldap) ;; + esac], + [enable_ldap=true] +) + +AM_CONDITIONAL(BUILD_LDAP, test x$enable_ldap != xfalse) +if test "$enable_ldap" = "true"; then + AC_CHECK_LIB(ldap,ldap_initialize, LDAP_LIBS="-lldap") + AC_SUBST(LDAP_LIBS) + AC_DEFINE(BUILD_LDAP,1,[Defined if LDAP build option enabled]) +fi + dnl conditionnal build of console interface. AC_ARG_ENABLE(console_ui, [AS_HELP_STRING([--enable-console_ui=[yes/no]], [Turn on or off compilation of console interface (default=yes)])], @@ -854,6 +872,7 @@ printf "* %-30s %s\n" "Tools" $build_tools printf "* %-30s %s\n" "Message storage" $enable_msg_storage printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp printf "* %-30s %s\n" "uPnP support" $build_upnp +printf "* %-30s %s\n" "LDAP support" $enable_ldap if test "$enable_tunnel" = "true" ; then printf "* %-30s %s\n" "Tunnel support" "true" diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index b6ed2ec32..928ffb084 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -48,11 +48,16 @@ liblinphone_la_SOURCES=\ message_storage.c \ info.c \ event.c event.h \ + contactprovider.c contactprovider.h \ $(GITVERSION_FILE) if BUILD_UPNP liblinphone_la_SOURCES+=upnp.c upnp.h endif + +if BUILD_LDAP +liblinphone_la_SOURCES+= ldap/ldapprovider.c ldap/ldapprovider.h +endif liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c bellesip_sal/sal_impl.h \ @@ -89,7 +94,8 @@ liblinphone_la_LIBADD= \ $(TUNNEL_LIBS) \ $(LIBSOUP_LIBS) \ $(SQLITE3_LIBS) \ - $(LIBXML2_LIBS) + $(LIBXML2_LIBS) \ + $(LDAP_LIBS) if ENABLE_TESTS diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index d8e7cb7ee..94ce56beb 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -15,23 +15,85 @@ */ #include "contactprovider.h" +#include -struct linphone_contact_provider { - belle_sip_object_t base; +/* LinphoneContactSearchRequest + */ + +void linphone_contact_search_init(LinphoneContactSearch* obj, + const char* predicate, + ContactSearchCallback cb, + void* cb_data) +{ + static unsigned int request_id_counter = 1; + obj->id = request_id_counter++; // unique id + obj->predicate = ms_strdup(predicate?predicate:""); + obj->cb = cb; + obj->data = cb_data; +} + +static void linphone_contact_search_destroy( LinphoneContactSearch* req) { + if( req->predicate ) ms_free(req->predicate); + ms_free(req); +} + +ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj) +{ + return obj->id; +} + +const char*linphone_contact_search_get_predicate(LinphoneContactSearch* obj) +{ + return obj->predicate; +} + +void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends) +{ + if( req->cb ) req->cb(req->id, friends, req->data); +} + +int linphone_contact_search_compare(const void* a, const void* b) { + LinphoneContactSearch *ra=((LinphoneContactSearch*)a); + LinphoneContactSearch *rb=((LinphoneContactSearch*)b); + return !(ra->id == rb->id); // return 0 if id is equal, 1 otherwise +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactSearch); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneContactSearch,belle_sip_object_t, + (belle_sip_object_destroy_t)linphone_contact_search_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + +/* + * LinphoneContactProvider + */ + + +void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc){ + obj->lc = lc; +} + +static void contact_provider_destroy(LinphoneContactProvider* obj){ + (void)obj; +} + + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactProvider); +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneContactProvider)= +{ + { + BELLE_SIP_VPTR_INIT(LinphoneContactProvider,belle_sip_object_t,TRUE), + (belle_sip_object_destroy_t) contact_provider_destroy, + NULL,/*no clone*/ + NULL,/*no marshal*/ + }, + "", + // Pure virtual + NULL, /* begin_search -> pure virtual */ + NULL /* cancel_search -> pure virtual */ }; -linphone_contact_provider_t* linphone_contact_provider_create() -{ - linphone_contact_provider_t* obj = belle_sip_object_new(linphone_contact_provider_t); - return obj; -} - -static void linphone_contact_provider_destroy() -{ - -} - -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(linphone_contact_provider_t); -BELLE_SIP_INSTANCIATE_VPTR(linphone_contact_provider_t, belle_sip_object_t, - linphone_contact_provider_destroy, NULL, NULL,FALSE); diff --git a/coreapi/contactprovider.h b/coreapi/contactprovider.h index b1a502b21..68c894fbf 100644 --- a/coreapi/contactprovider.h +++ b/coreapi/contactprovider.h @@ -17,10 +17,50 @@ #include #include "linphonecore.h" +/* LinphoneContactSearchRequest */ -typedef struct linphone_contact_provider linphone_contact_provider_t; -#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,linphone_contact_provider_t) +typedef unsigned int ContactSearchID; + +typedef void (*ContactSearchCallback)( ContactSearchID id, MSList* friends, void* data ); + +typedef struct { + ContactSearchID id; + char* predicate; + ContactSearchCallback cb; + void* data; +} LinphoneContactSearch; + +#define LINPHONE_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneContactSearch) +BELLE_SIP_DECLARE_VPTR(LinphoneContactSearch) +void linphone_contact_search_init(LinphoneContactSearch* obj, const char* predicate, ContactSearchCallback cb, void* cb_data); +ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj); +const char* linphone_contact_search_get_predicate(LinphoneContactSearch* obj); +void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends); -linphone_contact_provider_t* linphone_contact_provider_create(); + +/* LinphoneContactProvider */ + +struct _LinphoneContactProvider { + belle_sip_object_t base; + LinphoneCore* lc; +}; + +typedef struct _LinphoneContactProvider LinphoneContactProvider; +typedef LinphoneContactSearch* (*LinphoneContactProviderStartSearchMethod)( LinphoneContactProvider* thiz, const char* predicate, ContactSearchCallback cb, void* data ); +typedef unsigned int (*LinphoneContactProviderCancelSearchMethod)( LinphoneContactProvider* thiz, LinphoneContactSearch *request ); +#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneContactProvider) + +BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider,belle_sip_object_t) + const char* name; /*!< Name of the contact provider (LDAP, Google, ...) */ + + /* pure virtual methods: inheriting objects must implement these */ + LinphoneContactProviderStartSearchMethod begin_search; + LinphoneContactProviderCancelSearchMethod cancel_search; +BELLE_SIP_DECLARE_CUSTOM_VPTR_END + + +void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc); +LinphoneCore* linphone_contact_provider_get_core(LinphoneContactProvider* obj); +const char* linphone_contact_provider_get_name(LinphoneContactProvider* obj); diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c new file mode 100644 index 000000000..843cea918 --- /dev/null +++ b/coreapi/ldap/ldapprovider.c @@ -0,0 +1,290 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ldapprovider.h" +#include "linphonecore_utils.h" +#include "lpconfig.h" +#include + +struct _LinphoneLDAPContactSearch +{ + LDAP *ld; + int msgid; + char* filter; +}; + +#define MAX_RUNNING_REQUESTS 10 +#define FILTER_MAX_SIZE 512 +typedef struct { + int msgid; + LinphoneLDAPContactSearch* request; +} LDAPRequestEntry; + +struct _LinphoneLDAPContactProvider +{ + LDAP* ld; + //LDAPRequestEntry requests[MAX_RUNNING_REQUESTS]; + MSList* requests; + int req_count; + + // config + int use_tls; + char* auth_method; + char* username; + char* password; + + char* base_object; + char** attributes; + char* filter; + int timeout; + int deref_aliases; + int max_results; +}; + +/* ************************* + * LinphoneLDAPContactSearch + * *************************/ + +LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* cp, const char* predicate, ContactSearchCallback cb, void* cb_data) +{ + LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); + LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search); + linphone_contact_search_init(base, predicate, cb, cb_data); + search->ld = cp->ld; + search->filter = ms_malloc(FILTER_MAX_SIZE); + snprintf(search->filter, FILTER_MAX_SIZE-1, cp->filter, predicate); + search->filter[FILTER_MAX_SIZE-1] = 0; + struct timeval timeout = { cp->timeout, 0 }; + ldap_search_ext(search->ld, cp->base_object, LDAP_SCOPE_SUBTREE, search->filter, + cp->attributes, 0, NULL, NULL, &timeout, cp->max_results, &search->msgid ); + return search; +} + +static void linphone_ldap_contact_destroy( LinphoneLDAPContactSearch* obj ) +{ + (void)obj; +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactSearch); +BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch, + (belle_sip_object_destroy_t)linphone_ldap_contact_destroy, + NULL, + NULL, + TRUE +); + + +/* *************************** + * LinphoneLDAPContactProvider + * ***************************/ + +static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ) +{ + if(obj->auth_method) ms_free(obj->auth_method); + if(obj->username) ms_free(obj->username); + if(obj->password) ms_free(obj->password); + if(obj->base_object) ms_free(obj->base_object); + if(obj->attributes){ + int i=0; + for( ; obj->attributes[i]; i++){ + ms_free(obj->attributes[i]); + } + ms_free(obj->attributes); + } +} + +static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) +{ + if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL); + obj->ld = NULL; + linphone_ldap_contact_provider_conf_destroy(obj); +} + +static LinphoneLDAPContactSearch* linphone_ldap_begin_search(LinphoneLDAPContactProvider* obj, + const char* predicate, + ContactSearchCallback cb, + void* cb_data) +{ + LDAPRequestEntry* entry = ms_new0(LDAPRequestEntry,1); + if( entry){ + LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create(obj, predicate, cb, cb_data); + entry->msgid = request->msgid; + entry->request = request; + obj->requests = ms_list_append(obj->requests, entry); + obj->req_count++; + return request; + } else { + return NULL; + } +} + +static int linphone_ldap_request_entry_compare(const void*a, const void* b) +{ + const LDAPRequestEntry* ra = (const LDAPRequestEntry*)a; + const LDAPRequestEntry* rb = (const LDAPRequestEntry*)b; + return !(ra->msgid == rb->msgid); +} + +static unsigned int linphone_ldap_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req) +{ + LinphoneLDAPContactSearch* ldap_req = LINPHONE_LDAP_CONTACT_SEARCH(req); + LinphoneLDAPContactProvider* ldap_cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj); + LDAPRequestEntry dummy = { ldap_req->msgid, ldap_req }; + int ret = 1; + + MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare, &dummy); + if( list_entry ) { + ldap_cp->requests = ms_list_remove(ldap_cp->requests, list_entry); + ldap_cp->req_count--; + ms_free(list_entry); + ret = 0; // return OK if we found it in the monitored requests + } else { + ms_warning("Couldn't find ldap request %p (id %d) in monitoring.", ldap_req, ldap_req->msgid); + } + belle_sip_object_unref(req); + return ret; +} + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); + +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= +{ + { + { + BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE), + (belle_sip_object_destroy_t)linphone_ldap_contact_provider_destroy, + NULL, + NULL + }, + "LDAP", + (LinphoneContactProviderStartSearchMethod)linphone_ldap_begin_search, + (LinphoneContactProviderCancelSearchMethod)linphone_ldap_cancel_search + } +}; + +static bool_t linphone_ldap_contact_provider_iterate(void *data) +{ + LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data); + if( obj->ld && (obj->req_count >= 0) ){ + int wait_for_all_results = 1; + // never block + struct timeval timeout = {0,0}; + LDAPMessage* results = NULL; + + int res = ldap_result(obj->ld, LDAP_RES_ANY, wait_for_all_results, &timeout, &results); + + switch( res ){ + case -1: + { + ms_warning("Error in ldap_result : returned -1"); + break; + } + case 0: break; // nothing to do + case LDAP_RES_BIND: + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_SEARCH_REFERENCE: + case LDAP_RES_SEARCH_RESULT: + case LDAP_RES_MODIFY: + case LDAP_RES_ADD: + case LDAP_RES_DELETE: + case LDAP_RES_MODDN: + case LDAP_RES_COMPARE: + case LDAP_RES_EXTENDED: + case LDAP_RES_INTERMEDIATE: + { + ms_message("Got LDAP result type %x", res); + ldap_msgfree(results); + break; + } + default: + ms_message("Unhandled LDAP result %x", res); + break; + } + } + return TRUE; +} + +static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, LpConfig* config) +{ + const char* section="ldap"; + char* attributes_list, *saveptr, *attr; + unsigned int attr_count = 0, attr_idx = 0, i; + obj->use_tls = lp_config_get_int(config, section, "use_tls", 0); + obj->timeout = lp_config_get_int(config, section, "timeout", 10); + obj->deref_aliases = lp_config_get_int(config, section, "deref_aliases", 0); + obj->max_results = lp_config_get_int(config, section, "max_results", 50); + + // free any pre-existing char* conf values + linphone_ldap_contact_provider_conf_destroy(obj); + + + // parse the attributes list + attributes_list = ms_strdup(lp_config_get_string(config, section, "attributes", "telephoneNumber,givenName,sn")); + + // count attributes: + for( i=0; attributes_list[i]; i++) + { + if( attributes_list[i] == ',') attr_count++; + } + obj->attributes = ms_malloc0((attr_count+2) * sizeof(char*)); + + attr = strtok_r( attributes_list, ",", &saveptr ); + while( attr != NULL ){ + obj->attributes[attr_idx] = ms_strdup(attr); + attr_idx++; + attr = strtok_r(NULL, ",", &saveptr); + } + if( attr_idx == attr_count) + + + + obj->auth_method = ms_strdup(lp_config_get_string(config, section, "auth_method", "anonymous")); + obj->username = ms_strdup(lp_config_get_string(config, section, "username", "")); + obj->password = ms_strdup(lp_config_get_string(config, section, "password", "")); + obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "")); + +} + + +LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc) +{ + LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider); + linphone_contact_provider_init(LINPHONE_CONTACT_PROVIDER(obj), lc); + memset(obj->requests, MAX_RUNNING_REQUESTS, sizeof(LDAPRequestEntry)); + + int proto_version = LDAP_VERSION3; + const char* url = "localhost"; + ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name); + + linphone_ldap_contact_provider_loadconfig(obj, linphone_core_get_config(lc)); + + int ret = ldap_initialize(&(obj->ld),url); + + if( ret != LDAP_SUCCESS ){ + ms_error( "Problem initializing ldap on url '%s': %s", url, ldap_err2string(ret)); + linphone_ldap_contact_provider_destroy(obj); + return NULL; + } else if( (ret = ldap_set_option(obj->ld, LDAP_OPT_PROTOCOL_VERSION, &proto_version)) != LDAP_SUCCESS ){ + ms_error( "Problem setting protocol version %d: %s", proto_version, ldap_err2string(ret)); + linphone_ldap_contact_provider_destroy(obj); + return NULL; + } else { + // register our hook into iterate so that LDAP can do its magic asynchronously + linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); + } + return obj; +} + diff --git a/coreapi/ldap/ldapprovider.h b/coreapi/ldap/ldapprovider.h new file mode 100644 index 000000000..bea77554b --- /dev/null +++ b/coreapi/ldap/ldapprovider.h @@ -0,0 +1,42 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "contactprovider.h" + +#include + +typedef struct _LinphoneLDAPContactProvider LinphoneLDAPContactProvider; + +/* LinphoneLDAPContactSearch */ +typedef struct _LinphoneLDAPContactSearch LinphoneLDAPContactSearch; + +#define LINPHONE_LDAP_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactSearch) +BELLE_SIP_DECLARE_VPTR(LinphoneLDAPContactSearch) + +LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* ld, + const char* predicate, + ContactSearchCallback cb, + void* cb_data); + + +/* LinphoneLDAPContactProvider */ + +#define LINPHONE_LDAP_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactProvider) + +BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider,LinphoneContactProvider) +BELLE_SIP_DECLARE_CUSTOM_VPTR_END + +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d8a0e26db..e85b35f8b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2152,10 +2152,12 @@ LINPHONE_PUBLIC void linphone_core_set_video_display_filter(LinphoneCore *lc, co /** Contact Providers */ BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) -BELLE_SIP_TYPE_ID(linphone_contact_provider_t) +BELLE_SIP_TYPE_ID(LinphoneContactSearch), +BELLE_SIP_TYPE_ID(LinphoneContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) BELLE_SIP_DECLARE_TYPES_END -BELLE_SIP_DECLARE_VPTR(linphone_contact_provider_t) #ifdef __cplusplus } From f5c9d60d8823085b1a5a3f823c5d3c39eabe0b93 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 28 Nov 2013 16:58:15 +0100 Subject: [PATCH 003/439] Progress commit... --- coreapi/ldap/ldapprovider.c | 204 ++++++++++++++++++++++++++---------- 1 file changed, 150 insertions(+), 54 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 843cea918..79cb66b03 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -19,12 +19,6 @@ #include "lpconfig.h" #include -struct _LinphoneLDAPContactSearch -{ - LDAP *ld; - int msgid; - char* filter; -}; #define MAX_RUNNING_REQUESTS 10 #define FILTER_MAX_SIZE 512 @@ -33,18 +27,27 @@ typedef struct { LinphoneLDAPContactSearch* request; } LDAPRequestEntry; +typedef enum { + ANONYMOUS, + PLAIN, + SASL +} LDAPAuthMethod; + struct _LinphoneLDAPContactProvider { - LDAP* ld; - //LDAPRequestEntry requests[MAX_RUNNING_REQUESTS]; + LDAP* ld; MSList* requests; - int req_count; + uint req_count; + + // bind transaction + uint bind_msgid; // config int use_tls; - char* auth_method; + LDAPAuthMethod auth_method; char* username; char* password; + char* server; char* base_object; char** attributes; @@ -54,6 +57,14 @@ struct _LinphoneLDAPContactProvider int max_results; }; +struct _LinphoneLDAPContactSearch +{ + LDAP *ld; + int msgid; + char* filter; +}; + + /* ************************* * LinphoneLDAPContactSearch * *************************/ @@ -62,20 +73,38 @@ LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContac { LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search); + struct timeval timeout = { cp->timeout, 0 }; + linphone_contact_search_init(base, predicate, cb, cb_data); - search->ld = cp->ld; + + search->ld = cp->ld; + search->filter = ms_malloc(FILTER_MAX_SIZE); snprintf(search->filter, FILTER_MAX_SIZE-1, cp->filter, predicate); search->filter[FILTER_MAX_SIZE-1] = 0; - struct timeval timeout = { cp->timeout, 0 }; - ldap_search_ext(search->ld, cp->base_object, LDAP_SCOPE_SUBTREE, search->filter, - cp->attributes, 0, NULL, NULL, &timeout, cp->max_results, &search->msgid ); + + int ret = ldap_search_ext(search->ld, + cp->base_object, // base from which to start + LDAP_SCOPE_SUBTREE, + search->filter, // search predicate + cp->attributes, // which attributes to get + 0, // 0 = get attrs AND value, 1 = get attrs only + NULL, + NULL, + &timeout, // server timeout for the search + cp->max_results,// max result number + &search->msgid ); + if( ret != LDAP_SUCCESS ){ + ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret)); + belle_sip_object_unref(search); + return NULL; + } return search; } static void linphone_ldap_contact_destroy( LinphoneLDAPContactSearch* obj ) { - (void)obj; + if( obj->filter ) ms_free(obj->filter); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactSearch); @@ -90,13 +119,35 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch, /* *************************** * LinphoneLDAPContactProvider * ***************************/ +struct AuthMethodDescription{ + LDAPAuthMethod method; + const char* description; +}; + +static struct AuthMethodDescription ldap_auth_method_description[] = { + {ANONYMOUS, "anonymous"}, + {PLAIN, "plain"}, + {SASL, "sasl"}, + {0, NULL} +}; + +static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* description ) +{ + struct AuthMethodDescription* desc = ldap_auth_method_description; + while( desc && desc->description ){ + if( strcmp(description, desc->description) == 0) + return desc->method; + desc++; + } + return ANONYMOUS; +} static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ) { - if(obj->auth_method) ms_free(obj->auth_method); - if(obj->username) ms_free(obj->username); - if(obj->password) ms_free(obj->password); + if(obj->username) ms_free(obj->username); + if(obj->password) ms_free(obj->password); if(obj->base_object) ms_free(obj->base_object); + if(obj->attributes){ int i=0; for( ; obj->attributes[i]; i++){ @@ -113,17 +164,20 @@ static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* linphone_ldap_contact_provider_conf_destroy(obj); } -static LinphoneLDAPContactSearch* linphone_ldap_begin_search(LinphoneLDAPContactProvider* obj, - const char* predicate, - ContactSearchCallback cb, - void* cb_data) +static LinphoneLDAPContactSearch* +linphone_ldap_begin_search(LinphoneLDAPContactProvider* obj, + const char* predicate, + ContactSearchCallback cb, + void* cb_data) { LDAPRequestEntry* entry = ms_new0(LDAPRequestEntry,1); if( entry){ LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create(obj, predicate, cb, cb_data); + entry->msgid = request->msgid; entry->request = request; - obj->requests = ms_list_append(obj->requests, entry); + + obj->requests = ms_list_append(obj->requests, entry); obj->req_count++; return request; } else { @@ -158,33 +212,16 @@ static unsigned int linphone_ldap_cancel_search(LinphoneContactProvider* obj, Li return ret; } -BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); - -BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= -{ - { - { - BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE), - (belle_sip_object_destroy_t)linphone_ldap_contact_provider_destroy, - NULL, - NULL - }, - "LDAP", - (LinphoneContactProviderStartSearchMethod)linphone_ldap_begin_search, - (LinphoneContactProviderCancelSearchMethod)linphone_ldap_cancel_search - } -}; - static bool_t linphone_ldap_contact_provider_iterate(void *data) { LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data); - if( obj->ld && (obj->req_count >= 0) ){ - int wait_for_all_results = 1; + if( obj->ld && ((obj->req_count >= 0) || (obj->bind_msgid != 0) )){ + // never block struct timeval timeout = {0,0}; LDAPMessage* results = NULL; - int res = ldap_result(obj->ld, LDAP_RES_ANY, wait_for_all_results, &timeout, &results); + int res = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ALL, &timeout, &results); switch( res ){ case -1: @@ -193,7 +230,14 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) break; } case 0: break; // nothing to do - case LDAP_RES_BIND: + case LDAP_RES_BIND: + { + ms_message("iterate: LDAP_RES_BIND"); + if( ldap_msgid( results ) != obj->bind_msgid ) { + ms_error("Bad msgid"); + } + break; + } case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_SEARCH_RESULT: @@ -226,13 +270,19 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide obj->timeout = lp_config_get_int(config, section, "timeout", 10); obj->deref_aliases = lp_config_get_int(config, section, "deref_aliases", 0); obj->max_results = lp_config_get_int(config, section, "max_results", 50); + obj->auth_method = linphone_ldap_contact_provider_auth_method( lp_config_get_string(config, section, "auth_method", "anonymous")); + // free any pre-existing char* conf values linphone_ldap_contact_provider_conf_destroy(obj); - // parse the attributes list - attributes_list = ms_strdup(lp_config_get_string(config, section, "attributes", "telephoneNumber,givenName,sn")); + /* + * parse the attributes list + */ + attributes_list = ms_strdup(lp_config_get_string(config, section, + "attributes", + "telephoneNumber,givenName,sn")); // count attributes: for( i=0; attributes_list[i]; i++) @@ -240,6 +290,7 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide if( attributes_list[i] == ',') attr_count++; } obj->attributes = ms_malloc0((attr_count+2) * sizeof(char*)); + // 1 more for the first attr without ',', the other for the null-finished list attr = strtok_r( attributes_list, ",", &saveptr ); while( attr != NULL ){ @@ -247,17 +298,45 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide attr_idx++; attr = strtok_r(NULL, ",", &saveptr); } - if( attr_idx == attr_count) + if( attr_idx != attr_count+1) ms_error("Invalid attribute number!!! %d expected, got %d", attr_count+1, attr_idx); + ms_free(attributes_list); - - obj->auth_method = ms_strdup(lp_config_get_string(config, section, "auth_method", "anonymous")); obj->username = ms_strdup(lp_config_get_string(config, section, "username", "")); obj->password = ms_strdup(lp_config_get_string(config, section, "password", "")); obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "")); + obj->server = ms_strdup(lp_config_get_string(config, section, "server", "ldap://localhost:10389")); + } +static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) +{ + struct berval password = { strlen( obj->password), obj->password }; + int ret; + int bind_msgid = 0; + + switch( obj->auth_method ){ + case ANONYMOUS: + default: + { + ret = ldap_sasl_bind( obj->ld, obj->base_object, NULL, &password, NULL, NULL, &bind_msgid); + if( ret == LDAP_SUCCESS ) { + obj->bind_msgid = bind_msgid; + } else { + int err; + ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err); + ms_error("ldap_sasl_bind error %d (%s)", err, ldap_err2string(err) ); + } + break; + } + case SASL: + { + break; + } + } + return 0; +} LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc) { @@ -266,25 +345,42 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* memset(obj->requests, MAX_RUNNING_REQUESTS, sizeof(LDAPRequestEntry)); int proto_version = LDAP_VERSION3; - const char* url = "localhost"; ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name); linphone_ldap_contact_provider_loadconfig(obj, linphone_core_get_config(lc)); - int ret = ldap_initialize(&(obj->ld),url); + int ret = ldap_initialize(&(obj->ld),obj->server); if( ret != LDAP_SUCCESS ){ - ms_error( "Problem initializing ldap on url '%s': %s", url, ldap_err2string(ret)); - linphone_ldap_contact_provider_destroy(obj); + ms_error( "Problem initializing ldap on url '%s': %s", obj->server, ldap_err2string(ret)); + belle_sip_object_unref(obj); return NULL; } else if( (ret = ldap_set_option(obj->ld, LDAP_OPT_PROTOCOL_VERSION, &proto_version)) != LDAP_SUCCESS ){ ms_error( "Problem setting protocol version %d: %s", proto_version, ldap_err2string(ret)); - linphone_ldap_contact_provider_destroy(obj); + belle_sip_object_unref(obj); return NULL; } else { // register our hook into iterate so that LDAP can do its magic asynchronously + linphone_ldap_contact_provider_bind(obj); linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); } return obj; } + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); + +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= +{ + { + { + BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE), + (belle_sip_object_destroy_t)linphone_ldap_contact_provider_destroy, + NULL, + NULL + }, + "LDAP", + (LinphoneContactProviderStartSearchMethod)linphone_ldap_begin_search, + (LinphoneContactProviderCancelSearchMethod)linphone_ldap_cancel_search + } +}; From a1bbb890aa3e8896d8cfcc71a390f8154059b88c Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 29 Nov 2013 09:53:48 +0100 Subject: [PATCH 004/439] Progress --- coreapi/ldap/ldapprovider.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 79cb66b03..5d52cb795 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -212,6 +212,17 @@ static unsigned int linphone_ldap_cancel_search(LinphoneContactProvider* obj, Li return ret; } +static int linphone_ldap_parse_bind_results( LinphoneContactProvider* obj, LDAPMessage* results ) +{ + LinphoneLDAPContactProvider* cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj); + struct berval *servercreds; + int ret = ldap_parse_sasl_bind_result(cp->ld, results, &servercreds, 1); + if( ret != LDAP_SUCCESS ){ + ms_error("ldap_parse_sasl_bind_result failed") + } + return ret; +} + static bool_t linphone_ldap_contact_provider_iterate(void *data) { LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data); @@ -235,6 +246,9 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) ms_message("iterate: LDAP_RES_BIND"); if( ldap_msgid( results ) != obj->bind_msgid ) { ms_error("Bad msgid"); + } else { + linphone_ldap_parse_bind_results( obj, results ); + obj->bind_msgid = 0; } break; } @@ -320,7 +334,8 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj case ANONYMOUS: default: { - ret = ldap_sasl_bind( obj->ld, obj->base_object, NULL, &password, NULL, NULL, &bind_msgid); + char *auth = NULL; + ret = ldap_sasl_bind( obj->ld, obj->base_object, auth, &password, NULL, NULL, &bind_msgid); if( ret == LDAP_SUCCESS ) { obj->bind_msgid = bind_msgid; } else { @@ -360,7 +375,7 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* belle_sip_object_unref(obj); return NULL; } else { - // register our hook into iterate so that LDAP can do its magic asynchronously + // register our hook into iterate so that LDAP can do its magic asynchronously. linphone_ldap_contact_provider_bind(obj); linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); } From c17165ac9dd0a17a93dec03f661d5c381d5fbac7 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 2 Dec 2013 13:07:09 +0100 Subject: [PATCH 005/439] Progress commit: first ldap search results are now available. There's a test button in the ui to test a search. --- coreapi/contactprovider.c | 6 +- coreapi/contactprovider.h | 9 +- coreapi/ldap/ldapprovider.c | 338 ++++++++++++++++++++++++++---------- coreapi/linphonecore.c | 36 +++- coreapi/linphonecore.h | 9 + coreapi/private.h | 8 + gtk/loginframe.c | 14 ++ gtk/main.ui | 26 ++- 8 files changed, 348 insertions(+), 98 deletions(-) diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index 94ce56beb..96a941b1f 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -30,11 +30,13 @@ void linphone_contact_search_init(LinphoneContactSearch* obj, obj->predicate = ms_strdup(predicate?predicate:""); obj->cb = cb; obj->data = cb_data; + ms_message("LinphoneContactSearch@%p(id:%d, pred:%s, cb:%p, data:%p)", + obj, obj->id, obj->predicate, obj->cb, obj->data); } static void linphone_contact_search_destroy( LinphoneContactSearch* req) { + ms_message( "~LinphoneContactSearch(%p)", req); if( req->predicate ) ms_free(req->predicate); - ms_free(req); } ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj) @@ -49,7 +51,7 @@ const char*linphone_contact_search_get_predicate(LinphoneContactSearch* obj) void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends) { - if( req->cb ) req->cb(req->id, friends, req->data); + if( req->cb ) req->cb(req, friends, req->data); } int linphone_contact_search_compare(const void* a, const void* b) { diff --git a/coreapi/contactprovider.h b/coreapi/contactprovider.h index 68c894fbf..857bd1a8d 100644 --- a/coreapi/contactprovider.h +++ b/coreapi/contactprovider.h @@ -19,16 +19,13 @@ /* LinphoneContactSearchRequest */ -typedef unsigned int ContactSearchID; - -typedef void (*ContactSearchCallback)( ContactSearchID id, MSList* friends, void* data ); - -typedef struct { +struct _LinphoneContactSearch{ + belle_sip_object_t base; ContactSearchID id; char* predicate; ContactSearchCallback cb; void* data; -} LinphoneContactSearch; +}; #define LINPHONE_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneContactSearch) BELLE_SIP_DECLARE_VPTR(LinphoneContactSearch) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 5d52cb795..dcd4b22e8 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -22,10 +22,6 @@ #define MAX_RUNNING_REQUESTS 10 #define FILTER_MAX_SIZE 512 -typedef struct { - int msgid; - LinphoneLDAPContactSearch* request; -} LDAPRequestEntry; typedef enum { ANONYMOUS, @@ -35,19 +31,21 @@ typedef enum { struct _LinphoneLDAPContactProvider { + LinphoneContactProvider base; LDAP* ld; MSList* requests; uint req_count; - + // bind transaction uint bind_msgid; + struct berval *servercreds; // config int use_tls; LDAPAuthMethod auth_method; - char* username; - char* password; - char* server; + char* username; + char* password; + char* server; char* base_object; char** attributes; @@ -59,9 +57,11 @@ struct _LinphoneLDAPContactProvider struct _LinphoneLDAPContactSearch { - LDAP *ld; - int msgid; - char* filter; + LinphoneContactSearch base; + LDAP* ld; + int msgid; + char* filter; +// MSList* found_entries; }; @@ -70,6 +70,7 @@ struct _LinphoneLDAPContactSearch * *************************/ LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* cp, const char* predicate, ContactSearchCallback cb, void* cb_data) + { LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search); @@ -83,6 +84,8 @@ LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContac snprintf(search->filter, FILTER_MAX_SIZE-1, cp->filter, predicate); search->filter[FILTER_MAX_SIZE-1] = 0; + ms_message("Calling ldap_search_ext with predicate '%s' on base %s", search->filter, cp->base_object); + int ret = ldap_search_ext(search->ld, cp->base_object, // base from which to start LDAP_SCOPE_SUBTREE, @@ -98,12 +101,15 @@ LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContac ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret)); belle_sip_object_unref(search); return NULL; + } else { + ms_message("LinphoneLDAPContactSearch created @%p : msgid %d", search, search->msgid); } return search; } static void linphone_ldap_contact_destroy( LinphoneLDAPContactSearch* obj ) { + ms_message("~LinphoneLDAPContactSearch(%p)", obj); if( obj->filter ) ms_free(obj->filter); } @@ -130,6 +136,8 @@ static struct AuthMethodDescription ldap_auth_method_description[] = { {SASL, "sasl"}, {0, NULL} }; +static unsigned int linphone_ldap_cancel_search_from_msgid( LinphoneLDAPContactProvider* obj, int msgid ); +static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ); static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* description ) { @@ -142,11 +150,17 @@ static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* de return ANONYMOUS; } +static void linphone_ldap_contact_provider_destroy_request(void *req, void *dummy) +{ + belle_sip_object_unref(req); +} + static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ) { if(obj->username) ms_free(obj->username); if(obj->password) ms_free(obj->password); if(obj->base_object) ms_free(obj->base_object); + if(obj->filter) ms_free(obj->filter); if(obj->attributes){ int i=0; @@ -159,118 +173,133 @@ static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvi static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) { + // clean pending requests + ms_list_for_each2(obj->requests, linphone_ldap_contact_provider_destroy_request, 0); + if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL); obj->ld = NULL; + linphone_ldap_contact_provider_conf_destroy(obj); } -static LinphoneLDAPContactSearch* -linphone_ldap_begin_search(LinphoneLDAPContactProvider* obj, - const char* predicate, - ContactSearchCallback cb, - void* cb_data) + +static int linphone_ldap_parse_bind_results( LinphoneLDAPContactProvider* obj, LDAPMessage* results ) { - LDAPRequestEntry* entry = ms_new0(LDAPRequestEntry,1); - if( entry){ - LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create(obj, predicate, cb, cb_data); - - entry->msgid = request->msgid; - entry->request = request; - - obj->requests = ms_list_append(obj->requests, entry); - obj->req_count++; - return request; - } else { - return NULL; - } -} - -static int linphone_ldap_request_entry_compare(const void*a, const void* b) -{ - const LDAPRequestEntry* ra = (const LDAPRequestEntry*)a; - const LDAPRequestEntry* rb = (const LDAPRequestEntry*)b; - return !(ra->msgid == rb->msgid); -} - -static unsigned int linphone_ldap_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req) -{ - LinphoneLDAPContactSearch* ldap_req = LINPHONE_LDAP_CONTACT_SEARCH(req); - LinphoneLDAPContactProvider* ldap_cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj); - LDAPRequestEntry dummy = { ldap_req->msgid, ldap_req }; - int ret = 1; - - MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare, &dummy); - if( list_entry ) { - ldap_cp->requests = ms_list_remove(ldap_cp->requests, list_entry); - ldap_cp->req_count--; - ms_free(list_entry); - ret = 0; // return OK if we found it in the monitored requests - } else { - ms_warning("Couldn't find ldap request %p (id %d) in monitoring.", ldap_req, ldap_req->msgid); - } - belle_sip_object_unref(req); - return ret; -} - -static int linphone_ldap_parse_bind_results( LinphoneContactProvider* obj, LDAPMessage* results ) -{ - LinphoneLDAPContactProvider* cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj); - struct berval *servercreds; - int ret = ldap_parse_sasl_bind_result(cp->ld, results, &servercreds, 1); + int ret = ldap_parse_sasl_bind_result(obj->ld, results, NULL, 0); if( ret != LDAP_SUCCESS ){ - ms_error("ldap_parse_sasl_bind_result failed") + ms_error("ldap_parse_sasl_bind_result failed"); } return ret; } +static void linphone_ldap_handle_search_result( LinphoneLDAPContactProvider* cp, LinphoneLDAPContactSearch* req, LDAPMessage* message ) +{ + int msgtype = ldap_msgtype(message); + switch(msgtype){ + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_EXTENDED: + { + LDAPMessage *entry = ldap_first_entry(cp->ld, message); + while( entry != NULL ){ + + BerElement* ber = NULL; + char* dn = ldap_get_dn(cp->ld, entry); + char* attr = ldap_first_attribute(cp->ld, entry, &ber); + if( dn ){ + ms_message("search result: dn: %s", dn); + ldap_memfree(dn); + } + + while( attr ){ + struct berval** values = ldap_get_values_len(cp->ld, entry, attr); + struct berval** v = values; + while( *v && (*v)->bv_val && (*v)->bv_len ) + { + ms_message("%s -> %s", attr, (*v)->bv_val); + v++; + } + + if( values ) ldap_value_free_len(values); + + ldap_memfree(attr); + attr = ldap_next_attribute(cp->ld, entry, ber); + } + + if( ber ) ber_free(ber, 0); + + entry = ldap_next_entry(cp->ld, entry); + } + } + break; + + + default: ms_message("Unhandled message type %x", msgtype); break; + } +} + static bool_t linphone_ldap_contact_provider_iterate(void *data) { LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data); - if( obj->ld && ((obj->req_count >= 0) || (obj->bind_msgid != 0) )){ + if( obj->ld && ((obj->req_count > 0) || (obj->bind_msgid != 0) )){ // never block struct timeval timeout = {0,0}; LDAPMessage* results = NULL; - int res = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ALL, &timeout, &results); + int ret = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ALL, &timeout, &results); - switch( res ){ + if( ret != 0 && ret != -1) ms_message("ldap_result %x", ret); + + switch( ret ){ case -1: { - ms_warning("Error in ldap_result : returned -1"); + ms_warning("Error in ldap_result : returned -1 (req_count %d, bind_msgid %d): %s", obj->req_count, obj->bind_msgid, ldap_err2string(errno)); break; } case 0: break; // nothing to do - case LDAP_RES_BIND: + + case LDAP_RES_BIND: { ms_message("iterate: LDAP_RES_BIND"); if( ldap_msgid( results ) != obj->bind_msgid ) { ms_error("Bad msgid"); } else { linphone_ldap_parse_bind_results( obj, results ); - obj->bind_msgid = 0; + obj->bind_msgid = 0; // we're bound now, don't bother checking again } break; } + case LDAP_RES_SEARCH_RESULT: + case LDAP_RES_EXTENDED: case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: - case LDAP_RES_SEARCH_RESULT: + case LDAP_RES_INTERMEDIATE: + { + bool_t associated_req_found = FALSE; + LDAPMessage* message = ldap_first_message(obj->ld, results); + while( message != NULL ){ + LinphoneLDAPContactSearch* req = linphone_ldap_request_entry_search(obj, ldap_msgid(message)); + ms_message("Message @%p:id %d / type %x / associated request: %p", message, ldap_msgid(message), ldap_msgtype(message), req); + linphone_ldap_handle_search_result(obj, req, message ); + if( req ) associated_req_found = TRUE; + message = ldap_next_message(obj->ld, message); + } + if( associated_req_found) + linphone_ldap_cancel_search_from_msgid(obj, ldap_msgid(results)); + break; + } case LDAP_RES_MODIFY: case LDAP_RES_ADD: case LDAP_RES_DELETE: case LDAP_RES_MODDN: case LDAP_RES_COMPARE: - case LDAP_RES_EXTENDED: - case LDAP_RES_INTERMEDIATE: - { - ms_message("Got LDAP result type %x", res); - ldap_msgfree(results); - break; - } default: - ms_message("Unhandled LDAP result %x", res); + ms_message("Unhandled LDAP result %x", ret); break; } + + if( results ) + ldap_msgfree(results); } return TRUE; } @@ -290,13 +319,12 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide // free any pre-existing char* conf values linphone_ldap_contact_provider_conf_destroy(obj); - /* * parse the attributes list */ attributes_list = ms_strdup(lp_config_get_string(config, section, "attributes", - "telephoneNumber,givenName,sn")); + "telephoneNumber,givenName,sn,mobile,homePhone")); // count attributes: for( i=0; attributes_list[i]; i++) @@ -318,8 +346,9 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide obj->username = ms_strdup(lp_config_get_string(config, section, "username", "")); obj->password = ms_strdup(lp_config_get_string(config, section, "password", "")); - obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "")); + obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "dc=example,dc=com")); obj->server = ms_strdup(lp_config_get_string(config, section, "server", "ldap://localhost:10389")); + obj->filter = ms_strdup(lp_config_get_string(config, section, "filter", "uid=*%s*")); } @@ -329,7 +358,7 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj struct berval password = { strlen( obj->password), obj->password }; int ret; int bind_msgid = 0; - + switch( obj->auth_method ){ case ANONYMOUS: default: @@ -356,10 +385,9 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc) { LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider); - linphone_contact_provider_init(LINPHONE_CONTACT_PROVIDER(obj), lc); - memset(obj->requests, MAX_RUNNING_REQUESTS, sizeof(LDAPRequestEntry)); - int proto_version = LDAP_VERSION3; + + linphone_contact_provider_init((LinphoneContactProvider*)obj, lc); ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name); linphone_ldap_contact_provider_loadconfig(obj, linphone_core_get_config(lc)); @@ -382,6 +410,141 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* return obj; } +/** + * Search an LDAP request in the list of current LDAP requests to serve, only taking + * the msgid as a key to search. + */ +static int linphone_ldap_request_entry_compare_weak(const void*a, const void* b) +{ + const LinphoneLDAPContactSearch* ra = (const LinphoneLDAPContactSearch*)a; + const LinphoneLDAPContactSearch* rb = (const LinphoneLDAPContactSearch*)b; + return !(ra->msgid == rb->msgid); // 0 if equal +} + +/** + * Search an LDAP request in the list of current LDAP requests to serve, with strong search + * comparing both msgid and request pointer + */ +static int linphone_ldap_request_entry_compare_strong(const void*a, const void* b) +{ + const LinphoneLDAPContactSearch* ra = (const LinphoneLDAPContactSearch*)a; + const LinphoneLDAPContactSearch* rb = (const LinphoneLDAPContactSearch*)b; + return !(ra->msgid == rb->msgid) && !(ra == rb); +} + +static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ) +{ + LinphoneLDAPContactSearch dummy = { + .msgid = msgid + }; + + MSList* list_entry = ms_list_find_custom(obj->requests, linphone_ldap_request_entry_compare_weak, &dummy); + if( list_entry ) return list_entry->data; + else return NULL; +} + +static unsigned int linphone_ldap_cancel_search_from_msgid( LinphoneLDAPContactProvider* obj, int msgid ) +{ + int ret = 1; + LinphoneLDAPContactSearch dummy = { + .msgid = msgid + }; + MSList* list_entry = ms_list_find_custom(obj->requests, linphone_ldap_request_entry_compare_weak, &dummy); + + ms_message("Found entry for msgid %d @%p", msgid, list_entry); + + if( list_entry ) { + LinphoneLDAPContactSearch* entry = list_entry->data; + obj->requests = ms_list_remove_link(obj->requests, list_entry); + obj->req_count--; + belle_sip_object_unref(entry); + ret = 0; // return OK if we found it in the monitored requests + } else { + ms_warning("Couldn't find ldap request id %d in monitoring.", msgid); + } + return ret; +} + +static unsigned int linphone_ldap_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req) +{ + LinphoneLDAPContactSearch* ldap_req = LINPHONE_LDAP_CONTACT_SEARCH(req); + LinphoneLDAPContactProvider* ldap_cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj); + int ret = 1; + + MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare_strong, req); + if( list_entry ) { + ldap_cp->requests = ms_list_remove(ldap_cp->requests, list_entry); + ldap_cp->req_count--; + ret = 0; // return OK if we found it in the monitored requests + } else { + ms_warning("Couldn't find ldap request %p (id %d) in monitoring.", ldap_req, ldap_req->msgid); + } + belle_sip_object_unref(req); // unref request even if not found + return ret; +} + +static LinphoneLDAPContactSearch* linphone_ldap_begin_search ( LinphoneLDAPContactProvider* obj, + const char* predicate, + ContactSearchCallback cb, + void* cb_data ) +{ + LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create ( obj, predicate, cb, cb_data ); + + if ( request != NULL ) { + ms_message ( "Created search %d for '%s', msgid %d, @%p", obj->req_count, predicate, request->msgid, request ); + + obj->requests = ms_list_append ( obj->requests, request ); + obj->req_count++; + } + return request; +} + + +static int linphone_ldap_marshal(LinphoneLDAPContactProvider* obj, char* buff, size_t buff_size, size_t *offset) +{ + belle_sip_error_code error = BELLE_SIP_OK; + + error = belle_sip_snprintf(buff, buff_size, offset, "ld:%p,\n", obj->ld); + if(error!= BELLE_SIP_OK) return error; + + error = belle_sip_snprintf(buff, buff_size, offset, "req_count:%d,\n", obj->req_count); + if(error!= BELLE_SIP_OK) return error; + + error = belle_sip_snprintf(buff, buff_size, offset, "bind_msgid:%d,\n", obj->bind_msgid); + if(error!= BELLE_SIP_OK) return error; + + + error = belle_sip_snprintf(buff, buff_size, offset, + "CONFIG:\n" + "tls: %d \n" + "auth: %d \n" + "user: %s \n" + "pass: %s \n" + "server: %s \n" + "base: %s \n" + "filter: %s \n" + "timeout: %d \n" + "deref: %d \n" + "max_res: %d \n" + "attrs: ", + obj->use_tls, obj->auth_method, + obj->username, obj->password, obj->server, + obj->base_object, obj->filter, + obj->timeout, obj->deref_aliases, + obj->max_results); + if(error!= BELLE_SIP_OK) return error; + + char **attr = obj->attributes; + while( *attr ){ + error = belle_sip_snprintf(buff, buff_size, offset, "attr:%s\n", *attr); + if(error!= BELLE_SIP_OK) return error; + else attr++; + } + + return error; + +} + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); @@ -392,10 +555,11 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE), (belle_sip_object_destroy_t)linphone_ldap_contact_provider_destroy, NULL, - NULL + (belle_sip_object_marshal_t)linphone_ldap_marshal }, "LDAP", (LinphoneContactProviderStartSearchMethod)linphone_ldap_begin_search, (LinphoneContactProviderCancelSearchMethod)linphone_ldap_cancel_search } }; + diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9bafb93da..e05ecc6ce 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1338,6 +1338,12 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->tunnel=linphone_core_tunnel_new(lc); if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); #endif + +#ifdef BUILD_LDAP + lc->ldap =linphone_ldap_contact_provider_create(lc); + belle_sip_object_ref( lc->ldap ); +#endif + if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; @@ -5634,16 +5640,23 @@ static void linphone_core_uninit(LinphoneCore *lc) } #endif //BUILD_UPNP +#ifdef BUILD_LDAP + if( lc->ldap != NULL ) { + belle_sip_object_unref(lc->ldap); + lc->ldap = NULL; + } +#endif + 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 */ ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); lc->call_logs=ms_list_free(lc->call_logs); - + ms_list_for_each(lc->last_recv_msg_ids,ms_free); lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids); - + // Free struct variable if(lc->zrtp_secrets_cache != NULL) { ms_free(lc->zrtp_secrets_cache); @@ -6247,3 +6260,22 @@ void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){ } +LinphoneContactSearch* linphone_core_ldap_launch_search(LinphoneCore* lc, const char* predicate, ContactSearchCallback cb, void* userdata) +{ + if( lc->ldap ){ + LinphoneContactProvider* cp = LINPHONE_CONTACT_PROVIDER(lc->ldap); + LinphoneContactSearch* search = BELLE_SIP_OBJECT_VPTR(cp,LinphoneContactProvider)->begin_search(cp, predicate, cb, userdata); + char *desc = belle_sip_object_to_string(cp); + + if( desc) { + ms_message("ldap: %s", desc); + ms_free(desc); + } + + if(search){ + belle_sip_object_ref(search); + return search; + } + } + return NULL; +} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index e85b35f8b..657cd0de6 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2158,6 +2158,15 @@ BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) BELLE_SIP_DECLARE_TYPES_END +typedef unsigned int ContactSearchID; + +struct _LinphoneContactSearch; +typedef struct _LinphoneContactSearch LinphoneContactSearch; + +typedef void (*ContactSearchCallback)( LinphoneContactSearch* id, MSList* friends, void* data ); + + +LINPHONE_PUBLIC LinphoneContactSearch* linphone_core_ldap_launch_search(LinphoneCore* lc, const char* predicate, ContactSearchCallback cb, void* userdata); #ifdef __cplusplus } diff --git a/coreapi/private.h b/coreapi/private.h index e4ddd59c0..933bca104 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -74,6 +74,10 @@ extern "C" { #endif #endif +#ifdef BUILD_LDAP +#include "ldap/ldapprovider.h" +#endif + 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 */ @@ -655,6 +659,10 @@ struct _LinphoneCore #ifdef BUILD_UPNP UpnpContext *upnp; #endif //BUILD_UPNP + +#ifdef BUILD_LDAP + LinphoneLDAPContactProvider* ldap; +#endif //BUILD_LDAP }; diff --git a/gtk/loginframe.c b/gtk/loginframe.c index 45da5480f..50160a85a 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone.h" void linphone_gtk_login_frame_connect_clicked(GtkWidget *button); +void test_button_clicked_cb(GtkWidget *button); void linphone_gtk_exit_login_frame(void); enum { @@ -166,6 +167,19 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ linphone_gtk_load_identities(); } +void test_cb( LinphoneContactSearch* req, MSList* friends, void* data ) +{ + ms_message("LDAP Search CB received "); +} + + +void test_btn_clicked_cb(GtkWidget *button) +{ + ms_message("test_button_clicked_cb"); + LinphoneCore* core = linphone_gtk_get_core(); + linphone_core_ldap_launch_search(core, "mar", test_cb, (void*)0x12345678); +} + void linphone_gtk_internet_kind_changed(GtkWidget *combo){ int netkind_id=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); LinphoneCore *lc=linphone_gtk_get_core(); diff --git a/gtk/main.ui b/gtk/main.ui index ae1335c5d..f27fd79bd 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1063,6 +1063,21 @@ 0 + + + TEST + True + True + True + False + + + + False + False + 1 + + True @@ -1109,6 +1124,12 @@ 3 + + + + + + False @@ -1547,8 +1568,8 @@ - True True + True True False none @@ -1762,6 +1783,9 @@ 0 + + + True From 8aa375d637d86933729ec4115aa1a09e1569fed1 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 3 Dec 2013 10:52:00 +0100 Subject: [PATCH 006/439] Progress commit on LDAP: - we now create minphone contacts based on what the LDAP query returns, - added configuration for specifying which LDAP field corresponds to the SIP address and contact name - fixed some leaks in LDAP data extraction - modified the completion of the uribar to include LDAP results. We now insert them into the list when available. --- coreapi/ldap/ldapprovider.c | 264 +++++++++++++++++++++--------------- gtk/linphone.h | 5 + gtk/loginframe.c | 52 ++++++- gtk/main.c | 23 +++- 4 files changed, 231 insertions(+), 113 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index dcd4b22e8..d71989726 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -15,8 +15,10 @@ */ #include "ldapprovider.h" +#include "linphonecore.h" #include "linphonecore_utils.h" #include "lpconfig.h" + #include @@ -29,6 +31,11 @@ typedef enum { SASL } LDAPAuthMethod; +struct LDAPFriendData { + char* name; + char* sip; +}; + struct _LinphoneLDAPContactProvider { LinphoneContactProvider base; @@ -38,7 +45,7 @@ struct _LinphoneLDAPContactProvider // bind transaction uint bind_msgid; - struct berval *servercreds; + bool_t connected; // config int use_tls; @@ -49,6 +56,9 @@ struct _LinphoneLDAPContactProvider char* base_object; char** attributes; + char* sip_attr; + char* name_attr; + char* filter; int timeout; int deref_aliases; @@ -61,7 +71,8 @@ struct _LinphoneLDAPContactSearch LDAP* ld; int msgid; char* filter; -// MSList* found_entries; + bool_t complete; + MSList* found_entries; }; @@ -107,7 +118,7 @@ LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContac return search; } -static void linphone_ldap_contact_destroy( LinphoneLDAPContactSearch* obj ) +static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj ) { ms_message("~LinphoneLDAPContactSearch(%p)", obj); if( obj->filter ) ms_free(obj->filter); @@ -115,7 +126,7 @@ static void linphone_ldap_contact_destroy( LinphoneLDAPContactSearch* obj ) BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactSearch); BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch, - (belle_sip_object_destroy_t)linphone_ldap_contact_destroy, + (belle_sip_object_destroy_t)linphone_ldap_contact_search_destroy, NULL, NULL, TRUE @@ -136,8 +147,10 @@ static struct AuthMethodDescription ldap_auth_method_description[] = { {SASL, "sasl"}, {0, NULL} }; -static unsigned int linphone_ldap_cancel_search_from_msgid( LinphoneLDAPContactProvider* obj, int msgid ); static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ); +static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req); +static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); + static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* description ) { @@ -155,22 +168,6 @@ static void linphone_ldap_contact_provider_destroy_request(void *req, void *dumm belle_sip_object_unref(req); } -static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ) -{ - if(obj->username) ms_free(obj->username); - if(obj->password) ms_free(obj->password); - if(obj->base_object) ms_free(obj->base_object); - if(obj->filter) ms_free(obj->filter); - - if(obj->attributes){ - int i=0; - for( ; obj->attributes[i]; i++){ - ms_free(obj->attributes[i]); - } - ms_free(obj->attributes); - } -} - static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) { // clean pending requests @@ -188,52 +185,107 @@ static int linphone_ldap_parse_bind_results( LinphoneLDAPContactProvider* obj, L int ret = ldap_parse_sasl_bind_result(obj->ld, results, NULL, 0); if( ret != LDAP_SUCCESS ){ ms_error("ldap_parse_sasl_bind_result failed"); + } else { + obj->connected = TRUE; } return ret; } -static void linphone_ldap_handle_search_result( LinphoneLDAPContactProvider* cp, LinphoneLDAPContactSearch* req, LDAPMessage* message ) +static int linphone_ldap_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value) +{ + if( strcmp(attr_name, obj->name_attr ) == 0 ){ + ms_message("Got name attr: %s", attr_value); + lf->name = ms_strdup(attr_value); + } else if( strcmp(attr_name, obj->sip_attr) == 0 ) { + ms_message("Got sip attr: %s", attr_value); + lf->sip = ms_strdup(attr_value); + } + + // return 1 if the structure has enough data to create a linphone friend + if( lf->name && lf->sip ) return 1; + else return 0; + +} + +static void linphone_ldap_handle_search_result( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req, LDAPMessage* message ) { int msgtype = ldap_msgtype(message); + switch(msgtype){ - case LDAP_RES_SEARCH_ENTRY: - case LDAP_RES_EXTENDED: - { - LDAPMessage *entry = ldap_first_entry(cp->ld, message); - while( entry != NULL ){ - BerElement* ber = NULL; - char* dn = ldap_get_dn(cp->ld, entry); - char* attr = ldap_first_attribute(cp->ld, entry, &ber); - if( dn ){ - ms_message("search result: dn: %s", dn); - ldap_memfree(dn); - } + case LDAP_RES_SEARCH_ENTRY: + case LDAP_RES_EXTENDED: + { + LDAPMessage *entry = ldap_first_entry(obj->ld, message); + LinphoneCore* lc = LINPHONE_CONTACT_PROVIDER(obj)->lc; - while( attr ){ - struct berval** values = ldap_get_values_len(cp->ld, entry, attr); - struct berval** v = values; - while( *v && (*v)->bv_val && (*v)->bv_len ) - { - ms_message("%s -> %s", attr, (*v)->bv_val); - v++; - } + while( entry != NULL ){ - if( values ) ldap_value_free_len(values); + struct LDAPFriendData ldap_data = {0}; + bool_t all_found = FALSE; + BerElement* ber = NULL; + char* attr = ldap_first_attribute(obj->ld, entry, &ber); + char* dn = ldap_get_dn(obj->ld, entry); - ldap_memfree(attr); - attr = ldap_next_attribute(cp->ld, entry, ber); - } - if( ber ) ber_free(ber, 0); - - entry = ldap_next_entry(cp->ld, entry); + if( dn ){ + ms_message("search result: dn: %s", dn); + ldap_memfree(dn); } + + while( attr ){ + struct berval** values = ldap_get_values_len(obj->ld, entry, attr); + struct berval** it = values; + + while( values && *it && (*it)->bv_val && (*it)->bv_len ) + { + ms_message("%s -> %s", attr, (*it)->bv_val); + + all_found = linphone_ldap_complete_contact(obj, &ldap_data, attr, (*it)->bv_val); + if( all_found ) break; + + it++; + } + + if( values ) ldap_value_free_len(values); + ldap_memfree(attr); + + if( all_found ) break; + + attr = ldap_next_attribute(obj->ld, entry, ber); + } + + if( all_found ) { + LinphoneAddress* la = linphone_core_interpret_url(lc, ldap_data.sip); + if( la ){ + LinphoneFriend* lf = linphone_core_create_friend(lc); + linphone_friend_set_address(lf, la); + linphone_friend_set_name(lf, ldap_data.name); + req->found_entries = ms_list_append(req->found_entries, lf); + ms_message("Added friend %s / %s", ldap_data.name, ldap_data.sip); + ms_free(ldap_data.sip); + ms_free(ldap_data.name); + } + } + + if( ber ) ber_free(ber, 0); + + entry = ldap_next_entry(obj->ld, entry); } - break; + } + break; + + case LDAP_RES_SEARCH_RESULT: + { + // this one is received when a request is finished + req->complete = TRUE; + linphone_contact_search_invoke_cb(LINPHONE_CONTACT_SEARCH(req), req->found_entries); + } + break; - default: ms_message("Unhandled message type %x", msgtype); break; + + default: ms_message("Unhandled message type %x", msgtype); break; } } @@ -275,17 +327,14 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: { - bool_t associated_req_found = FALSE; LDAPMessage* message = ldap_first_message(obj->ld, results); + LinphoneLDAPContactSearch* req = linphone_ldap_request_entry_search(obj, ldap_msgid(message)); while( message != NULL ){ - LinphoneLDAPContactSearch* req = linphone_ldap_request_entry_search(obj, ldap_msgid(message)); ms_message("Message @%p:id %d / type %x / associated request: %p", message, ldap_msgid(message), ldap_msgtype(message), req); linphone_ldap_handle_search_result(obj, req, message ); - if( req ) associated_req_found = TRUE; message = ldap_next_message(obj->ld, message); } - if( associated_req_found) - linphone_ldap_cancel_search_from_msgid(obj, ldap_msgid(results)); + if( req ) linphone_ldap_contact_provider_cancel_search(LINPHONE_CONTACT_PROVIDER(obj), LINPHONE_CONTACT_SEARCH(req)); break; } case LDAP_RES_MODIFY: @@ -304,21 +353,47 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) return TRUE; } +static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ) +{ + if(obj->username) ms_free(obj->username); + if(obj->password) ms_free(obj->password); + if(obj->base_object) ms_free(obj->base_object); + if(obj->filter) ms_free(obj->filter); + if(obj->sip_attr) ms_free(obj->sip_attr); + if(obj->name_attr) ms_free(obj->name_attr); + + if(obj->attributes){ + int i=0; + for( ; obj->attributes[i]; i++){ + ms_free(obj->attributes[i]); + } + ms_free(obj->attributes); + } +} + static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, LpConfig* config) { const char* section="ldap"; char* attributes_list, *saveptr, *attr; unsigned int attr_count = 0, attr_idx = 0, i; - obj->use_tls = lp_config_get_int(config, section, "use_tls", 0); - obj->timeout = lp_config_get_int(config, section, "timeout", 10); - obj->deref_aliases = lp_config_get_int(config, section, "deref_aliases", 0); - obj->max_results = lp_config_get_int(config, section, "max_results", 50); - obj->auth_method = linphone_ldap_contact_provider_auth_method( lp_config_get_string(config, section, "auth_method", "anonymous")); + obj->use_tls = lp_config_get_int(config, section, "use_tls", 0); + obj->timeout = lp_config_get_int(config, section, "timeout", 10); + obj->deref_aliases = lp_config_get_int(config, section, "deref_aliases", 0); + obj->max_results = lp_config_get_int(config, section, "max_results", 50); + obj->auth_method = linphone_ldap_contact_provider_auth_method( lp_config_get_string(config, section, "auth_method", "anonymous")); // free any pre-existing char* conf values linphone_ldap_contact_provider_conf_destroy(obj); + obj->username = ms_strdup(lp_config_get_string(config, section, "username", "")); + obj->password = ms_strdup(lp_config_get_string(config, section, "password", "")); + obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "dc=example,dc=com")); + obj->server = ms_strdup(lp_config_get_string(config, section, "server", "ldap://localhost:10389")); + obj->filter = ms_strdup(lp_config_get_string(config, section, "filter", "uid=*%s*")); + obj->name_attr = ms_strdup(lp_config_get_string(config, section, "name_attribute", "givenName")); + obj->sip_attr = ms_strdup(lp_config_get_string(config, section, "sip_attribute", "mobile")); + /* * parse the attributes list */ @@ -327,12 +402,12 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide "telephoneNumber,givenName,sn,mobile,homePhone")); // count attributes: - for( i=0; attributes_list[i]; i++) - { + for( i=0; attributes_list[i]; i++) { if( attributes_list[i] == ',') attr_count++; } - obj->attributes = ms_malloc0((attr_count+2) * sizeof(char*)); + // 1 more for the first attr without ',', the other for the null-finished list + obj->attributes = ms_malloc0((attr_count+2) * sizeof(char*)); attr = strtok_r( attributes_list, ",", &saveptr ); while( attr != NULL ){ @@ -343,14 +418,6 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide if( attr_idx != attr_count+1) ms_error("Invalid attribute number!!! %d expected, got %d", attr_count+1, attr_idx); ms_free(attributes_list); - - obj->username = ms_strdup(lp_config_get_string(config, section, "username", "")); - obj->password = ms_strdup(lp_config_get_string(config, section, "password", "")); - obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "dc=example,dc=com")); - obj->server = ms_strdup(lp_config_get_string(config, section, "server", "ldap://localhost:10389")); - obj->filter = ms_strdup(lp_config_get_string(config, section, "filter", "uid=*%s*")); - - } static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) @@ -443,29 +510,7 @@ static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( Lin else return NULL; } -static unsigned int linphone_ldap_cancel_search_from_msgid( LinphoneLDAPContactProvider* obj, int msgid ) -{ - int ret = 1; - LinphoneLDAPContactSearch dummy = { - .msgid = msgid - }; - MSList* list_entry = ms_list_find_custom(obj->requests, linphone_ldap_request_entry_compare_weak, &dummy); - - ms_message("Found entry for msgid %d @%p", msgid, list_entry); - - if( list_entry ) { - LinphoneLDAPContactSearch* entry = list_entry->data; - obj->requests = ms_list_remove_link(obj->requests, list_entry); - obj->req_count--; - belle_sip_object_unref(entry); - ret = 0; // return OK if we found it in the monitored requests - } else { - ms_warning("Couldn't find ldap request id %d in monitoring.", msgid); - } - return ret; -} - -static unsigned int linphone_ldap_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req) +static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req) { LinphoneLDAPContactSearch* ldap_req = LINPHONE_LDAP_CONTACT_SEARCH(req); LinphoneLDAPContactProvider* ldap_cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj); @@ -473,7 +518,7 @@ static unsigned int linphone_ldap_cancel_search(LinphoneContactProvider* obj, Li MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare_strong, req); if( list_entry ) { - ldap_cp->requests = ms_list_remove(ldap_cp->requests, list_entry); + ldap_cp->requests = ms_list_remove_link(ldap_cp->requests, list_entry); ldap_cp->req_count--; ret = 0; // return OK if we found it in the monitored requests } else { @@ -516,27 +561,30 @@ static int linphone_ldap_marshal(LinphoneLDAPContactProvider* obj, char* buff, s error = belle_sip_snprintf(buff, buff_size, offset, "CONFIG:\n" - "tls: %d \n" - "auth: %d \n" - "user: %s \n" - "pass: %s \n" - "server: %s \n" - "base: %s \n" - "filter: %s \n" + "tls: %d \n" + "auth: %d \n" + "user: %s \n" + "pass: %s \n" + "server: %s \n" + "base: %s \n" + "filter: %s \n" "timeout: %d \n" - "deref: %d \n" + "deref: %d \n" "max_res: %d \n" - "attrs: ", + "sip_attr:%s \n" + "name_attr:%s \n" + "attrs:\n", obj->use_tls, obj->auth_method, obj->username, obj->password, obj->server, obj->base_object, obj->filter, obj->timeout, obj->deref_aliases, - obj->max_results); + obj->max_results, + obj->sip_attr, obj->name_attr); if(error!= BELLE_SIP_OK) return error; char **attr = obj->attributes; while( *attr ){ - error = belle_sip_snprintf(buff, buff_size, offset, "attr:%s\n", *attr); + error = belle_sip_snprintf(buff, buff_size, offset, "- %s\n", *attr); if(error!= BELLE_SIP_OK) return error; else attr++; } @@ -559,7 +607,7 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= }, "LDAP", (LinphoneContactProviderStartSearchMethod)linphone_ldap_begin_search, - (LinphoneContactProviderCancelSearchMethod)linphone_ldap_cancel_search + (LinphoneContactProviderCancelSearchMethod)linphone_ldap_contact_provider_cancel_search } }; diff --git a/gtk/linphone.h b/gtk/linphone.h index 67fa27ebf..2b2eba531 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -46,6 +46,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define LINPHONE_VERSION LINPHONE_VERSION_DATE #endif +enum { + COMPLETION_HISTORY, + COMPLETION_LDAP +}; + GdkPixbuf * create_pixbuf(const gchar *filename); GdkPixbufAnimation *create_pixbuf_animation(const gchar *filename); void add_pixmap_directory(const gchar *directory); diff --git a/gtk/loginframe.c b/gtk/loginframe.c index 50160a85a..2aa55d9dc 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -169,7 +169,52 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ void test_cb( LinphoneContactSearch* req, MSList* friends, void* data ) { - ms_message("LDAP Search CB received "); + ms_message("LDAP Search CB received:"); + GtkEntry* uribar = GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")); + GtkTreeModel* model = gtk_entry_completion_get_model(gtk_entry_get_completion(uribar)); + GtkListStore* list = GTK_LIST_STORE(model); + GtkTreeIter iter; + + + + // clear completion list from previous LDAP completion suggestions + if (!gtk_tree_model_get_iter_first(model,&iter)) return; + do { + int type; + char* url; + bool_t valid = TRUE; + gtk_tree_model_get(model,&iter,1,&type,0,&url,-1); + if (type == COMPLETION_LDAP) { + ms_message("Removing entry for %s", url?url:"NULL"); + valid = gtk_list_store_remove(list, &iter); + } else { + ms_message("Keep entry for %s (type %d)", url?url:"NULL", type); + } + + if( url ) g_free(url); + if( !valid ) break; + + }while(gtk_tree_model_iter_next(model,&iter)); + + while( friends ){ + LinphoneFriend* lf = friends->data; + if( lf ) { + const LinphoneAddress* la = linphone_friend_get_address(lf); + if( la ){ + char *addr = linphone_address_as_string(la); + + if( addr ){ + ms_message("Match: name=%s, addr=%s", linphone_friend_get_name(lf), addr); + gtk_list_store_insert_with_values(list, &iter, -1, + 0, addr, + 1, COMPLETION_LDAP, -1); + ms_free(addr); + } + } + } + friends = friends->next; + } + gtk_entry_completion_complete(gtk_entry_get_completion(uribar)); } @@ -177,7 +222,10 @@ void test_btn_clicked_cb(GtkWidget *button) { ms_message("test_button_clicked_cb"); LinphoneCore* core = linphone_gtk_get_core(); - linphone_core_ldap_launch_search(core, "mar", test_cb, (void*)0x12345678); + GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"); + const gchar* pred = gtk_entry_buffer_get_text(gtk_entry_get_buffer((GtkEntry*)uri_bar)); + + linphone_core_ldap_launch_search(core, pred, test_cb, (void*)0x12345678); } void linphone_gtk_internet_kind_changed(GtkWidget *combo){ diff --git a/gtk/main.c b/gtk/main.c index d8a8a2ede..9bab5b833 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -629,12 +629,28 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){ return TRUE; } +static gboolean uribar_completion_matchfunc(GtkEntryCompletion *completion, const gchar *key, GtkTreeIter *iter, gpointer user_data){ + char* address = NULL; + gboolean ret = FALSE; + gchar *tmp= NULL; + gtk_tree_model_get(gtk_entry_completion_get_model(completion),iter,0,&address,-1); + ms_message("In matchFunc(): key=%s, addr=%s",key,address); + + tmp = g_utf8_casefold(address,-1); + if (tmp){ + if (strstr(tmp,key)) + ret=TRUE; + g_free(tmp); + } + return ret; +} + static void load_uri_history(){ GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")); char key[20]; int i; GtkEntryCompletion *gep=gtk_entry_completion_new(); - GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING); + GtkListStore *model=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_INT); for (i=0;;i++){ const char *uri; snprintf(key,sizeof(key),"uri%i",i); @@ -642,13 +658,14 @@ static void load_uri_history(){ if (uri!=NULL) { GtkTreeIter iter; gtk_list_store_append(model,&iter); - gtk_list_store_set(model,&iter,0,uri,-1); + gtk_list_store_set(model,&iter,0,uri,1,COMPLETION_HISTORY,-1); if (i==0) gtk_entry_set_text(uribar,uri); } else break; } gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model)); gtk_entry_completion_set_text_column(gep,0); + gtk_entry_completion_set_match_func(gep,uribar_completion_matchfunc, NULL, NULL); gtk_entry_set_completion(uribar,gep); } @@ -697,7 +714,7 @@ static void completion_add_text(GtkEntry *entry, const char *text){ } /* and prepend it on top of the list */ gtk_list_store_prepend(GTK_LIST_STORE(model),&iter); - gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,1,COMPLETION_HISTORY,-1); save_uri_history(); } From cfbd9b8429118730f63bd049886264a110a45b19 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 4 Dec 2013 09:13:40 +0100 Subject: [PATCH 007/439] The LDAP suggestions are now correctly displayed in the suggestions --- coreapi/ldap/ldapprovider.c | 66 +++++++++++++------------ gtk/loginframe.c | 61 ----------------------- gtk/main.c | 97 ++++++++++++++++++++++++++++++++++++- gtk/main.ui | 15 ------ 4 files changed, 132 insertions(+), 107 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index d71989726..34de6f5a9 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -73,6 +73,7 @@ struct _LinphoneLDAPContactSearch char* filter; bool_t complete; MSList* found_entries; + int found_count; }; @@ -80,7 +81,7 @@ struct _LinphoneLDAPContactSearch * LinphoneLDAPContactSearch * *************************/ -LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* cp, const char* predicate, ContactSearchCallback cb, void* cb_data) +LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* cp, const char* predicate, ContactSearchCallback cb, void* cb_data) { LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); @@ -118,9 +119,16 @@ LinphoneLDAPContactSearch*linphone_ldap_contact_search_create(LinphoneLDAPContac return search; } +void linphone_ldap_contact_search_destroy_friend( void* entry ) +{ + linphone_friend_destroy((LinphoneFriend*)entry); +} + static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj ) { ms_message("~LinphoneLDAPContactSearch(%p)", obj); + ms_list_for_each(obj->found_entries, linphone_ldap_contact_search_destroy_friend); + obj->found_entries = ms_list_free(obj->found_entries); if( obj->filter ) ms_free(obj->filter); } @@ -136,6 +144,11 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch, /* *************************** * LinphoneLDAPContactProvider * ***************************/ +static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ); +static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req); +static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); + +/* Authentication methods */ struct AuthMethodDescription{ LDAPAuthMethod method; const char* description; @@ -147,10 +160,6 @@ static struct AuthMethodDescription ldap_auth_method_description[] = { {SASL, "sasl"}, {0, NULL} }; -static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ); -static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req); -static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); - static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* description ) { @@ -163,7 +172,7 @@ static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* de return ANONYMOUS; } -static void linphone_ldap_contact_provider_destroy_request(void *req, void *dummy) +static void linphone_ldap_contact_provider_destroy_request(void *req) { belle_sip_object_unref(req); } @@ -171,7 +180,7 @@ static void linphone_ldap_contact_provider_destroy_request(void *req, void *dumm static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) { // clean pending requests - ms_list_for_each2(obj->requests, linphone_ldap_contact_provider_destroy_request, 0); + ms_list_for_each(obj->requests, linphone_ldap_contact_provider_destroy_request); if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL); obj->ld = NULL; @@ -179,8 +188,7 @@ static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* linphone_ldap_contact_provider_conf_destroy(obj); } - -static int linphone_ldap_parse_bind_results( LinphoneLDAPContactProvider* obj, LDAPMessage* results ) +static int linphone_ldap_contact_provider_parse_bind_results( LinphoneLDAPContactProvider* obj, LDAPMessage* results ) { int ret = ldap_parse_sasl_bind_result(obj->ld, results, NULL, 0); if( ret != LDAP_SUCCESS ){ @@ -191,23 +199,23 @@ static int linphone_ldap_parse_bind_results( LinphoneLDAPContactProvider* obj, L return ret; } -static int linphone_ldap_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value) +static int linphone_ldap_contact_provider_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value) { if( strcmp(attr_name, obj->name_attr ) == 0 ){ - ms_message("Got name attr: %s", attr_value); lf->name = ms_strdup(attr_value); } else if( strcmp(attr_name, obj->sip_attr) == 0 ) { - ms_message("Got sip attr: %s", attr_value); lf->sip = ms_strdup(attr_value); } // return 1 if the structure has enough data to create a linphone friend - if( lf->name && lf->sip ) return 1; - else return 0; + if( lf->name && lf->sip ) + return 1; + else + return 0; } -static void linphone_ldap_handle_search_result( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req, LDAPMessage* message ) +static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req, LDAPMessage* message ) { int msgtype = ldap_msgtype(message); @@ -222,7 +230,7 @@ static void linphone_ldap_handle_search_result( LinphoneLDAPContactProvider* obj while( entry != NULL ){ struct LDAPFriendData ldap_data = {0}; - bool_t all_found = FALSE; + bool_t contact_complete = FALSE; BerElement* ber = NULL; char* attr = ldap_first_attribute(obj->ld, entry, &ber); char* dn = ldap_get_dn(obj->ld, entry); @@ -241,8 +249,8 @@ static void linphone_ldap_handle_search_result( LinphoneLDAPContactProvider* obj { ms_message("%s -> %s", attr, (*it)->bv_val); - all_found = linphone_ldap_complete_contact(obj, &ldap_data, attr, (*it)->bv_val); - if( all_found ) break; + contact_complete = linphone_ldap_contact_provider_complete_contact(obj, &ldap_data, attr, (*it)->bv_val); + if( contact_complete ) break; it++; } @@ -250,18 +258,19 @@ static void linphone_ldap_handle_search_result( LinphoneLDAPContactProvider* obj if( values ) ldap_value_free_len(values); ldap_memfree(attr); - if( all_found ) break; + if( contact_complete ) break; attr = ldap_next_attribute(obj->ld, entry, ber); } - if( all_found ) { + if( contact_complete ) { LinphoneAddress* la = linphone_core_interpret_url(lc, ldap_data.sip); if( la ){ LinphoneFriend* lf = linphone_core_create_friend(lc); linphone_friend_set_address(lf, la); linphone_friend_set_name(lf, ldap_data.name); req->found_entries = ms_list_append(req->found_entries, lf); + req->found_count++; ms_message("Added friend %s / %s", ldap_data.name, ldap_data.sip); ms_free(ldap_data.sip); ms_free(ldap_data.name); @@ -284,7 +293,6 @@ static void linphone_ldap_handle_search_result( LinphoneLDAPContactProvider* obj break; - default: ms_message("Unhandled message type %x", msgtype); break; } } @@ -298,7 +306,7 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) struct timeval timeout = {0,0}; LDAPMessage* results = NULL; - int ret = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ALL, &timeout, &results); + int ret = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ONE, &timeout, &results); if( ret != 0 && ret != -1) ms_message("ldap_result %x", ret); @@ -316,25 +324,25 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) if( ldap_msgid( results ) != obj->bind_msgid ) { ms_error("Bad msgid"); } else { - linphone_ldap_parse_bind_results( obj, results ); + linphone_ldap_contact_provider_parse_bind_results( obj, results ); obj->bind_msgid = 0; // we're bound now, don't bother checking again } break; } - case LDAP_RES_SEARCH_RESULT: case LDAP_RES_EXTENDED: case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_REFERENCE: case LDAP_RES_INTERMEDIATE: + case LDAP_RES_SEARCH_RESULT: { LDAPMessage* message = ldap_first_message(obj->ld, results); LinphoneLDAPContactSearch* req = linphone_ldap_request_entry_search(obj, ldap_msgid(message)); while( message != NULL ){ ms_message("Message @%p:id %d / type %x / associated request: %p", message, ldap_msgid(message), ldap_msgtype(message), req); - linphone_ldap_handle_search_result(obj, req, message ); + linphone_ldap_contact_provider_handle_search_result(obj, req, message ); message = ldap_next_message(obj->ld, message); } - if( req ) linphone_ldap_contact_provider_cancel_search(LINPHONE_CONTACT_PROVIDER(obj), LINPHONE_CONTACT_SEARCH(req)); + if( req && ret == LDAP_RES_SEARCH_RESULT) linphone_ldap_contact_provider_cancel_search(LINPHONE_CONTACT_PROVIDER(obj), LINPHONE_CONTACT_SEARCH(req)); break; } case LDAP_RES_MODIFY: @@ -501,9 +509,8 @@ static int linphone_ldap_request_entry_compare_strong(const void*a, const void* static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ) { - LinphoneLDAPContactSearch dummy = { - .msgid = msgid - }; + LinphoneLDAPContactSearch dummy = {}; + dummy.msgid = msgid; MSList* list_entry = ms_list_find_custom(obj->requests, linphone_ldap_request_entry_compare_weak, &dummy); if( list_entry ) return list_entry->data; @@ -558,7 +565,6 @@ static int linphone_ldap_marshal(LinphoneLDAPContactProvider* obj, char* buff, s error = belle_sip_snprintf(buff, buff_size, offset, "bind_msgid:%d,\n", obj->bind_msgid); if(error!= BELLE_SIP_OK) return error; - error = belle_sip_snprintf(buff, buff_size, offset, "CONFIG:\n" "tls: %d \n" diff --git a/gtk/loginframe.c b/gtk/loginframe.c index 2aa55d9dc..ef4ae9e05 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -167,67 +167,6 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ linphone_gtk_load_identities(); } -void test_cb( LinphoneContactSearch* req, MSList* friends, void* data ) -{ - ms_message("LDAP Search CB received:"); - GtkEntry* uribar = GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")); - GtkTreeModel* model = gtk_entry_completion_get_model(gtk_entry_get_completion(uribar)); - GtkListStore* list = GTK_LIST_STORE(model); - GtkTreeIter iter; - - - - // clear completion list from previous LDAP completion suggestions - if (!gtk_tree_model_get_iter_first(model,&iter)) return; - do { - int type; - char* url; - bool_t valid = TRUE; - gtk_tree_model_get(model,&iter,1,&type,0,&url,-1); - if (type == COMPLETION_LDAP) { - ms_message("Removing entry for %s", url?url:"NULL"); - valid = gtk_list_store_remove(list, &iter); - } else { - ms_message("Keep entry for %s (type %d)", url?url:"NULL", type); - } - - if( url ) g_free(url); - if( !valid ) break; - - }while(gtk_tree_model_iter_next(model,&iter)); - - while( friends ){ - LinphoneFriend* lf = friends->data; - if( lf ) { - const LinphoneAddress* la = linphone_friend_get_address(lf); - if( la ){ - char *addr = linphone_address_as_string(la); - - if( addr ){ - ms_message("Match: name=%s, addr=%s", linphone_friend_get_name(lf), addr); - gtk_list_store_insert_with_values(list, &iter, -1, - 0, addr, - 1, COMPLETION_LDAP, -1); - ms_free(addr); - } - } - } - friends = friends->next; - } - gtk_entry_completion_complete(gtk_entry_get_completion(uribar)); -} - - -void test_btn_clicked_cb(GtkWidget *button) -{ - ms_message("test_button_clicked_cb"); - LinphoneCore* core = linphone_gtk_get_core(); - GtkWidget *uri_bar=linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"); - const gchar* pred = gtk_entry_buffer_get_text(gtk_entry_get_buffer((GtkEntry*)uri_bar)); - - linphone_core_ldap_launch_search(core, pred, test_cb, (void*)0x12345678); -} - void linphone_gtk_internet_kind_changed(GtkWidget *combo){ int netkind_id=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); LinphoneCore *lc=linphone_gtk_get_core(); diff --git a/gtk/main.c b/gtk/main.c index 9bab5b833..870c1d40e 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -69,7 +69,7 @@ void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpoi static gboolean linphone_gtk_auto_answer(LinphoneCall *call); void linphone_gtk_status_icon_set_blinking(gboolean val); void _linphone_gtk_enable_video(gboolean val); - +void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data); #ifndef HAVE_GTK_OSX static gint main_window_x=0; @@ -642,6 +642,10 @@ static gboolean uribar_completion_matchfunc(GtkEntryCompletion *completion, cons ret=TRUE; g_free(tmp); } + + if( address) + g_free(address); + return ret; } @@ -665,8 +669,11 @@ static void load_uri_history(){ } gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model)); gtk_entry_completion_set_text_column(gep,0); + gtk_entry_completion_set_popup_completion(gep, TRUE); gtk_entry_completion_set_match_func(gep,uribar_completion_matchfunc, NULL, NULL); + gtk_entry_completion_set_minimum_key_length(gep,3); gtk_entry_set_completion(uribar,gep); + g_signal_connect (G_OBJECT (uribar), "changed", G_CALLBACK(linphone_gtk_on_uribar_changed), NULL); } static void save_uri_history(){ @@ -718,6 +725,94 @@ static void completion_add_text(GtkEntry *entry, const char *text){ save_uri_history(); } +void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* friends, void* data ) +{ + GtkTreeIter iter; + GtkEntry* uribar = GTK_ENTRY(data); + GtkEntryCompletion* compl = gtk_entry_get_completion(uribar); + GtkTreeModel* model = gtk_entry_completion_get_model(compl); + GtkListStore* list = GTK_LIST_STORE(model); + gboolean valid; + + // clear completion list from previous non-history completion suggestions + valid = gtk_tree_model_get_iter_first(model,&iter); + while(valid) + { + char* url; + int type; + gtk_tree_model_get(model,&iter, 0,&url, 1,&type, -1); + + if (type != COMPLETION_HISTORY) { + valid = gtk_list_store_remove(list, &iter); + } else { + valid = gtk_tree_model_iter_next(model,&iter); + } + + if( url ) g_free(url); + if( !valid ) break; + } + + // add new non-history related matches + while( friends ){ + LinphoneFriend* lf = friends->data; + if( lf ) { + const LinphoneAddress* la = linphone_friend_get_address(lf); + if( la ){ + char *addr = linphone_address_as_string(la); + + if( addr ){ + ms_message("[LDAP]Insert match: %s", addr); + gtk_list_store_insert_with_values(list, &iter, -1, + 0, addr, + 1, COMPLETION_LDAP, -1); + ms_free(addr); + } + } + } + friends = friends->next; + } + gtk_entry_completion_complete(compl); + + // Gtk bug? we need to emit a "changed" signal so that the completion appears if + // the list of results was previously empty + g_signal_handlers_block_by_func(uribar, linphone_gtk_on_uribar_changed, NULL); + g_signal_emit_by_name(uribar, "changed"); + g_signal_handlers_unblock_by_func(uribar, linphone_gtk_on_uribar_changed, NULL); +} + +struct CompletionTimeout { + guint timeout_id; +}; + +static gboolean launch_contact_provider_search(void *userdata) +{ + LinphoneCore* core = linphone_gtk_get_core(); + GtkWidget* uribar = GTK_WIDGET(userdata); + const gchar* predicate = gtk_entry_get_text((GtkEntry*)uribar); + + if( strlen(predicate) >= 3 ){ // don't search too small predicates + ms_message("launch_contact_provider_search"); + linphone_core_ldap_launch_search(core, predicate, on_contact_provider_search_results, uribar); + } + return FALSE; +} + +void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) +{ + gchar* text = gtk_editable_get_chars(uribar, 0,-1); + gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout")); + ms_message("URIBAR changed, new text: %s, userdata %p uribar @%p", text, user_data, uribar); + if( text ) g_free(text); + + + if( timeout != 0 ) { + g_source_remove(timeout); + } + timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar); + + gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) ); +} + bool_t linphone_gtk_video_enabled(void){ const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core()); return vpol->automatically_accept && vpol->automatically_initiate; diff --git a/gtk/main.ui b/gtk/main.ui index f27fd79bd..05461b6fc 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1063,21 +1063,6 @@ 0 - - - TEST - True - True - True - False - - - - False - False - 1 - - True From 26fc766c44e70d8773efe7125e40a9121345acd8 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 5 Dec 2013 15:23:23 +0100 Subject: [PATCH 008/439] Add BELLE_SIP flags to the help programs. --- coreapi/help/Makefile.am | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index 9d35b40a4..9d3c2475a 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -53,7 +53,8 @@ LINPHONE_TUTOS=$(helloworld_SOURCES) helloworld_LDADD=$(top_builddir)/coreapi/liblinphone.la \ $(MEDIASTREAMER_LIBS) \ - $(ORTP_LIBS) + $(ORTP_LIBS) \ + $(BELLESIP_LIBS) registration_SOURCES=registration.c LINPHONE_TUTOS+=$(registration_SOURCES) @@ -85,7 +86,8 @@ AM_CFLAGS=\ -DLOG_DOMAIN=\"LinphoneCore\" \ $(IPV6_CFLAGS) \ -DORTP_INET6 \ - $(VIDEO_CFLAGS) + $(VIDEO_CFLAGS) \ + $(BELLESIP_CFLAGS) tutodir=$(datadir)/tutorials/linphone From 031a08b750c22dfbf2cf39c596ce740450bb8661 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 5 Dec 2013 17:56:48 +0100 Subject: [PATCH 009/439] Introducing the dictionary type in linphone, inheriting from belle_sip_dict_t. --- coreapi/Makefile.am | 1 + coreapi/dict.c | 159 +++++++++++++++++++++++++++++++++++++++++ coreapi/linphonecore.h | 34 +++++++++ 3 files changed, 194 insertions(+) create mode 100644 coreapi/dict.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 928ffb084..228b7698b 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -49,6 +49,7 @@ liblinphone_la_SOURCES=\ info.c \ event.c event.h \ contactprovider.c contactprovider.h \ + dict.c \ $(GITVERSION_FILE) if BUILD_UPNP diff --git a/coreapi/dict.c b/coreapi/dict.c new file mode 100644 index 000000000..69b2bb4ee --- /dev/null +++ b/coreapi/dict.c @@ -0,0 +1,159 @@ +/* +linphone +Copyright (C) 2009 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" + +#include +#include +#include + + +/** + * @addtogroup linphone_dict + * @{ +**/ + + +LinphoneDictionary* linphone_dictionary_new() +{ + return belle_sip_dict_create(); +} + +LinphoneDictionary* linphone_dictionary_clone(const LinphoneDictionary* src) +{ + LinphoneDictionary* cloned = linphone_dictionary_new(); + if( cloned ){ + belle_sip_dict_clone(src, cloned); + } + return cloned; +} + +LinphoneDictionary* linphone_dictionary_ref(LinphoneDictionary* obj) +{ + return BELLE_SIP_DICT(belle_sip_object_ref(obj)); +} + +void linphone_dictionary_unref(LinphoneDictionary *obj) +{ + belle_sip_object_unref(obj); +} + +void linphone_dictionary_set_int(LinphoneDictionary* obj, const char* key, int value) +{ + belle_sip_dict_set_int(obj, key, value); +} + +int linphone_dictionary_get_int(LinphoneDictionary* obj, const char* key, int default_value) +{ + return belle_sip_dict_get_int(obj, key, default_value); +} + +void linphone_dictionary_set_string(LinphoneDictionary* obj, const char* key, const char*value) +{ + belle_sip_dict_set_string(obj, key, value); +} + +const char* linphone_dictionary_get_string(LinphoneDictionary* obj, const char* key, const char* default_value) +{ + return belle_sip_dict_get_string(obj, key, default_value); +} + +void linphone_dictionary_set_int64(LinphoneDictionary* obj, const char* key, int64_t value) +{ + belle_sip_dict_set_int64(obj, key, value); +} + +int64_t linphone_dictionary_get_int64(LinphoneDictionary* obj, const char* key, int64_t default_value) +{ + return belle_sip_dict_get_int64(obj, key, default_value); +} + +int linphone_dictionary_remove(LinphoneDictionary* obj, const char* key) +{ + return belle_sip_dict_remove(obj, key); +} + +void linphone_dictionary_clear(LinphoneDictionary* obj) +{ + belle_sip_dict_clear(obj); +} + +int linphone_dictionary_haskey(LinphoneDictionary* obj, const char* key) +{ + return belle_sip_dict_haskey(obj, key); +} + +void linphone_dictionary_foreach(const LinphoneDictionary* obj, void (*apply_func)(const char*, void*, void*), void* userdata) +{ + return belle_sip_dict_foreach(obj, apply_func, userdata); +} + +struct lp_config_to_dict { + const char* section; + const LpConfig* config; + LinphoneDictionary* dict; +}; + +static void lp_config_section_to_dict_cb(const char*key, struct lp_config_to_dict* userdata) +{ + const char* value = lp_config_get_string(userdata->config, userdata->section, key, ""); + linphone_dictionary_set_string(userdata->dict, key, value); +} + +LinphoneDictionary* lp_config_section_to_dict(const LpConfig* lpconfig, const char* section) +{ + LinphoneDictionary* dict = NULL; + struct lp_config_to_dict fd; + fd.config = lpconfig; + fd.section = section; + + dict = linphone_dictionary_new(); + fd.dict = dict; + + lp_config_for_each_entry(lpconfig, section, + (void (*)(const char*, void*))lp_config_section_to_dict_cb, + &fd); + + return dict; +} + +struct lp_config_from_dict { + const char* section; + LpConfig* config; +}; + +static void lp_config_dict_dump_cb( const char* key, void* value, void* userdata) +{ + struct lp_config_from_dict* fd= (struct lp_config_from_dict*)userdata; + lp_config_set_string(fd->config, fd->section, key, (const char*)value); +} + +void lp_config_load_dict_to_section(LpConfig* lpconfig, const char* section, const LinphoneDictionary* dict) +{ + struct lp_config_from_dict pvdata = { section, lpconfig }; + linphone_dictionary_foreach(dict,lp_config_dict_dump_cb, &pvdata); +} + + + +/** + * @} +**/ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 657cd0de6..d45ad7f85 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -33,6 +33,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" #include +#include #define LINPHONE_IPADDR_SIZE 64 #define LINPHONE_HOSTNAME_SIZE 128 @@ -120,6 +121,8 @@ typedef enum _LinphoneTransportType LinphoneTransportType; */ typedef struct SalAddress LinphoneAddress; +typedef struct belle_sip_dict LinphoneDictionary; + /** * The LinphoneContent struct holds data that can be embedded in a signaling message. * @ingroup misc @@ -183,6 +186,37 @@ typedef enum _LinphoneReason LinphoneReason; **/ const char *linphone_reason_to_string(LinphoneReason err); + +/* linphone dictionary */ +LINPHONE_PUBLIC LinphoneDictionary* linphone_dictionary_new(); +LinphoneDictionary * linphone_dictionary_clone(const LinphoneDictionary* src); +LinphoneDictionary * linphone_dictionary_ref(LinphoneDictionary* obj); +void linphone_dictionary_unref(LinphoneDictionary* obj); +LINPHONE_PUBLIC void linphone_dictionary_set_int(LinphoneDictionary* obj, const char* key, int value); +LINPHONE_PUBLIC int linphone_dictionary_get_int(LinphoneDictionary* obj, const char* key, int default_value); +LINPHONE_PUBLIC void linphone_dictionary_set_string(LinphoneDictionary* obj, const char* key, const char*value); +LINPHONE_PUBLIC const char* linphone_dictionary_get_string(LinphoneDictionary* obj, const char* key, const char* default_value); +LINPHONE_PUBLIC void linphone_dictionary_set_int64(LinphoneDictionary* obj, const char* key, int64_t value); +LINPHONE_PUBLIC int64_t linphone_dictionary_get_int64(LinphoneDictionary* obj, const char* key, int64_t default_value); +LINPHONE_PUBLIC int linphone_dictionary_remove(LinphoneDictionary* obj, const char* key); +LINPHONE_PUBLIC void linphone_dictionary_clear(LinphoneDictionary* obj); +LINPHONE_PUBLIC int linphone_dictionary_haskey(LinphoneDictionary* obj, const char* key); +LINPHONE_PUBLIC void linphone_dictionary_foreach( const LinphoneDictionary* obj, void (*apply_func)(const char*key, void* value, void* userdata), void* userdata); +/** + * Converts a config section into a dictionary. + * @return a #LinphoneDictionary with all the keys from a section, or NULL if the section doesn't exist + * @ingroup misc + */ +LinphoneDictionary* lp_config_section_to_dict( const LpConfig* lpconfig, const char* section ); + +/** + * Loads a dictionary into a section of the lpconfig. If the section doesn't exist it is created. + * Overwrites existing keys, creates non-existing keys. + * @ingroup misc + */ +void lp_config_load_dict_to_section( LpConfig* lpconfig, const char* section, const LinphoneDictionary* dict); + + #ifdef IN_LINPHONE #include "linphonefriend.h" #include "event.h" From eadc6025f153f6e4325eeb0d2b916a777f80caa5 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 5 Dec 2013 18:00:33 +0100 Subject: [PATCH 010/439] 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 73da787c6dc7f1dc3bd40c2de40492a24964adbe Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 5 Dec 2013 18:01:00 +0100 Subject: [PATCH 011/439] Progress commit on dictionary integration in LDAP --- coreapi/ldap/ldapprovider.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 34de6f5a9..7f49c21b7 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -18,6 +18,7 @@ #include "linphonecore.h" #include "linphonecore_utils.h" #include "lpconfig.h" +#include #include @@ -39,6 +40,8 @@ struct LDAPFriendData { struct _LinphoneLDAPContactProvider { LinphoneContactProvider base; + LinphoneDictionary* config; + LDAP* ld; MSList* requests; uint req_count; @@ -185,6 +188,8 @@ static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL); obj->ld = NULL; + if( obj->config ) linphone_dictionary_unref(obj->config); + linphone_ldap_contact_provider_conf_destroy(obj); } @@ -379,6 +384,24 @@ static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvi } } +static bool_t linphone_ldap_contact_provider_valid_config(LinphoneLDAPContactProvider* obj) +{ + bool_t valid = linphone_dictionary_haskey(obj->config, "use_tls") && + linphone_dictionary_haskey(obj->config, "timeout") && + linphone_dictionary_haskey(obj->config, "deref_aliases") && + linphone_dictionary_haskey(obj->config, "max_results") && + linphone_dictionary_haskey(obj->config, "auth_method") && + linphone_dictionary_haskey(obj->config, "username") && + linphone_dictionary_haskey(obj->config, "password") && + linphone_dictionary_haskey(obj->config, "base_object") && + linphone_dictionary_haskey(obj->config, "server") && + linphone_dictionary_haskey(obj->config, "filter") && + linphone_dictionary_haskey(obj->config, "name_attribute") && + linphone_dictionary_haskey(obj->config, "sip_attribute") && + linphone_dictionary_haskey(obj->config, "attributes"); + return valid; +} + static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, LpConfig* config) { const char* section="ldap"; @@ -397,7 +420,7 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide obj->username = ms_strdup(lp_config_get_string(config, section, "username", "")); obj->password = ms_strdup(lp_config_get_string(config, section, "password", "")); obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "dc=example,dc=com")); - obj->server = ms_strdup(lp_config_get_string(config, section, "server", "ldap://localhost:10389")); + obj->server = ms_strdup(lp_config_get_string(config, section, "server", "ldap://192.168.0.230:10389")); obj->filter = ms_strdup(lp_config_get_string(config, section, "filter", "uid=*%s*")); obj->name_attr = ms_strdup(lp_config_get_string(config, section, "name_attribute", "givenName")); obj->sip_attr = ms_strdup(lp_config_get_string(config, section, "sip_attribute", "mobile")); @@ -463,6 +486,8 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* int proto_version = LDAP_VERSION3; linphone_contact_provider_init((LinphoneContactProvider*)obj, lc); + + obj->config = linphone_dictionary_ref(linphone_dictionary_new()); ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name); linphone_ldap_contact_provider_loadconfig(obj, linphone_core_get_config(lc)); From ffffb5f80fdf63d324acc96b3d05a7f33d8d70d2 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 3 Dec 2013 11:26:09 +0100 Subject: [PATCH 012/439] 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 31c8585caed80adaccd6f9648ae74947830a0d8e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Dec 2013 10:50:09 +0100 Subject: [PATCH 013/439] 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 e7256e06b..5dfd53264 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) @@ -821,6 +825,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 228b7698b..7d728492a 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -88,6 +88,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 ad0d48554ee2a849d8138bbabfbe5b8a7a3aa91b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Dec 2013 14:29:27 +0100 Subject: [PATCH 014/439] 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 67a542a46a2f46c5fefd2aec7b9f637c742eb86c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Dec 2013 15:44:44 +0100 Subject: [PATCH 015/439] 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 e03a53dea293ec6f22dc5d0fb2038806df6aacac Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 09:02:29 +0100 Subject: [PATCH 016/439] 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 f0f24be45458e1c943ff5f53e488518aecfbb00e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 12:39:36 +0100 Subject: [PATCH 017/439] 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 5f6e15dbc775c77c930f67fdab65bcaff6ac0c42 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Dec 2013 12:47:45 +0100 Subject: [PATCH 018/439] 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 bb424c7841e677c57bc1132200c36c8db7e16281 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 14:07:06 +0100 Subject: [PATCH 019/439] 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 f9a26ab18916cbfcf13949e188fb8839b948c506 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 22:04:33 +0100 Subject: [PATCH 020/439] 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 5dfd53264..19087a244 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 80fad6d93e624c01cb583863c05966c8f581d7f7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Dec 2013 14:52:57 +0100 Subject: [PATCH 021/439] 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 e05ecc6ce..f52283cb6 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 d45ad7f85..9f57d1ce3 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1400,6 +1400,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 92c2c49d7683e5ca4e5ba0e28f3cac5e54fd8508 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 5 Dec 2013 16:47:36 +0100 Subject: [PATCH 022/439] 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 cfc100243ba1d9b37e814f7c1a416652d0b605ec Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 6 Dec 2013 14:31:07 +0100 Subject: [PATCH 023/439] Use LinphoneDictionary instead of lpconfig for creating LDAP provider. --- coreapi/ldap/ldapprovider.c | 149 ++++++++++++++++++++++-------------- coreapi/ldap/ldapprovider.h | 2 +- coreapi/linphonecore.c | 21 ----- coreapi/linphonecore.h | 2 - gtk/linphone.h | 6 ++ gtk/main.c | 47 ++++++++++-- 6 files changed, 140 insertions(+), 87 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 7f49c21b7..3bab710b2 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -175,7 +175,7 @@ static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* de return ANONYMOUS; } -static void linphone_ldap_contact_provider_destroy_request(void *req) +static void linphone_ldap_contact_provider_destroy_request_cb(void *req) { belle_sip_object_unref(req); } @@ -183,7 +183,7 @@ static void linphone_ldap_contact_provider_destroy_request(void *req) static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) { // clean pending requests - ms_list_for_each(obj->requests, linphone_ldap_contact_provider_destroy_request); + ms_list_for_each(obj->requests, linphone_ldap_contact_provider_destroy_request_cb); if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL); obj->ld = NULL; @@ -368,13 +368,6 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ) { - if(obj->username) ms_free(obj->username); - if(obj->password) ms_free(obj->password); - if(obj->base_object) ms_free(obj->base_object); - if(obj->filter) ms_free(obj->filter); - if(obj->sip_attr) ms_free(obj->sip_attr); - if(obj->name_attr) ms_free(obj->name_attr); - if(obj->attributes){ int i=0; for( ; obj->attributes[i]; i++){ @@ -384,53 +377,87 @@ static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvi } } -static bool_t linphone_ldap_contact_provider_valid_config(LinphoneLDAPContactProvider* obj) +static char* required_config_keys[] = { + // connection + "server", + "use_tls", + "auth_method", + "username", + "password", + + // search + "base_object", + "filter", + "name_attribute", + "sip_attribute", + "attributes", + + // misc + "timeout", + "max_results", + "deref_aliases", + NULL +}; + +static bool_t linphone_ldap_contact_provider_valid_config(LinphoneDictionary* dict) { - bool_t valid = linphone_dictionary_haskey(obj->config, "use_tls") && - linphone_dictionary_haskey(obj->config, "timeout") && - linphone_dictionary_haskey(obj->config, "deref_aliases") && - linphone_dictionary_haskey(obj->config, "max_results") && - linphone_dictionary_haskey(obj->config, "auth_method") && - linphone_dictionary_haskey(obj->config, "username") && - linphone_dictionary_haskey(obj->config, "password") && - linphone_dictionary_haskey(obj->config, "base_object") && - linphone_dictionary_haskey(obj->config, "server") && - linphone_dictionary_haskey(obj->config, "filter") && - linphone_dictionary_haskey(obj->config, "name_attribute") && - linphone_dictionary_haskey(obj->config, "sip_attribute") && - linphone_dictionary_haskey(obj->config, "attributes"); + char** config_name = required_config_keys; + + bool_t valid = TRUE; + bool_t has_key; + + while(*config_name ){ + has_key = linphone_dictionary_haskey(dict, *config_name); + if( !has_key ) ms_error("Missing LDAP config value for '%s'", *config_name); + valid &= has_key; + } return valid; } -static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, LpConfig* config) +static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, const LinphoneDictionary* dict) { - const char* section="ldap"; char* attributes_list, *saveptr, *attr; unsigned int attr_count = 0, attr_idx = 0, i; - obj->use_tls = lp_config_get_int(config, section, "use_tls", 0); - obj->timeout = lp_config_get_int(config, section, "timeout", 10); - obj->deref_aliases = lp_config_get_int(config, section, "deref_aliases", 0); - obj->max_results = lp_config_get_int(config, section, "max_results", 50); - obj->auth_method = linphone_ldap_contact_provider_auth_method( lp_config_get_string(config, section, "auth_method", "anonymous")); + if( !linphone_ldap_contact_provider_valid_config(dict) ) return; - // free any pre-existing char* conf values + // free any pre-existing attributes values linphone_ldap_contact_provider_conf_destroy(obj); + if( obj->config ) linphone_dictionary_unref(obj->config); - obj->username = ms_strdup(lp_config_get_string(config, section, "username", "")); - obj->password = ms_strdup(lp_config_get_string(config, section, "password", "")); - obj->base_object = ms_strdup(lp_config_get_string(config, section, "base_object", "dc=example,dc=com")); - obj->server = ms_strdup(lp_config_get_string(config, section, "server", "ldap://192.168.0.230:10389")); - obj->filter = ms_strdup(lp_config_get_string(config, section, "filter", "uid=*%s*")); - obj->name_attr = ms_strdup(lp_config_get_string(config, section, "name_attribute", "givenName")); - obj->sip_attr = ms_strdup(lp_config_get_string(config, section, "sip_attribute", "mobile")); + // clone new config into the dictionary + obj->config = linphone_dictionary_clone(dict); + linphone_dictionary_ref(obj->config); + + + obj->use_tls = linphone_dictionary_get_int(obj->config, "use_tls", 0); + obj->timeout = linphone_dictionary_get_int(obj->config, "timeout", 10); + obj->deref_aliases = linphone_dictionary_get_int(obj->config, "deref_aliases", 0); + obj->max_results = linphone_dictionary_get_int(obj->config, "max_results", 50); + obj->username = linphone_dictionary_get_string(obj->config, "username", ""); + obj->password = linphone_dictionary_get_string(obj->config, "password", ""); + obj->base_object = linphone_dictionary_get_string(obj->config, "base_object", "dc=example,dc=com"); + obj->server = linphone_dictionary_get_string(obj->config, "server", "ldap://192.168.0.230:10389"); + obj->filter = linphone_dictionary_get_string(obj->config, "filter", "uid=*%s*"); + obj->name_attr = linphone_dictionary_get_string(obj->config, "name_attribute", "givenName"); + obj->sip_attr = linphone_dictionary_get_string(obj->config, "sip_attribute", "mobile"); + + /* + * Get authentication method + */ + obj->auth_method = + linphone_ldap_contact_provider_auth_method( + linphone_dictionary_get_string(obj->config, "auth_method", "anonymous") + ); /* * parse the attributes list */ - attributes_list = ms_strdup(lp_config_get_string(config, section, - "attributes", - "telephoneNumber,givenName,sn,mobile,homePhone")); + attributes_list = ms_strdup( + linphone_dictionary_get_string(obj->config, + "attributes", + "telephoneNumber,givenName,sn,mobile,homePhone") + ); // count attributes: for( i=0; attributes_list[i]; i++) { @@ -453,7 +480,8 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) { - struct berval password = { strlen( obj->password), obj->password }; + const char* password_str = linphone_dictionary_get_string(obj, "password", ""); + struct berval password = { strlen( password_str ), password_str }; int ret; int bind_msgid = 0; @@ -480,32 +508,37 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj return 0; } -LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc) +LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config) { LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider); int proto_version = LDAP_VERSION3; linphone_contact_provider_init((LinphoneContactProvider*)obj, lc); - obj->config = linphone_dictionary_ref(linphone_dictionary_new()); ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name); - linphone_ldap_contact_provider_loadconfig(obj, linphone_core_get_config(lc)); - - int ret = ldap_initialize(&(obj->ld),obj->server); - - if( ret != LDAP_SUCCESS ){ - ms_error( "Problem initializing ldap on url '%s': %s", obj->server, ldap_err2string(ret)); + if( !linphone_ldap_contact_provider_valid_config(config) ) { + ms_error( "Invalid configuration for LDAP, aborting creation"); belle_sip_object_unref(obj); - return NULL; - } else if( (ret = ldap_set_option(obj->ld, LDAP_OPT_PROTOCOL_VERSION, &proto_version)) != LDAP_SUCCESS ){ - ms_error( "Problem setting protocol version %d: %s", proto_version, ldap_err2string(ret)); - belle_sip_object_unref(obj); - return NULL; + obj = NULL; } else { - // register our hook into iterate so that LDAP can do its magic asynchronously. - linphone_ldap_contact_provider_bind(obj); - linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); + linphone_ldap_contact_provider_loadconfig(obj, config); + + int ret = ldap_initialize(&(obj->ld),obj->server); + + if( ret != LDAP_SUCCESS ){ + ms_error( "Problem initializing ldap on url '%s': %s", obj->server, ldap_err2string(ret)); + belle_sip_object_unref(obj); + obj = NULL; + } else if( (ret = ldap_set_option(obj->ld, LDAP_OPT_PROTOCOL_VERSION, &proto_version)) != LDAP_SUCCESS ){ + ms_error( "Problem setting protocol version %d: %s", proto_version, ldap_err2string(ret)); + belle_sip_object_unref(obj); + obj = NULL; + } else { + // register our hook into iterate so that LDAP can do its magic asynchronously. + linphone_ldap_contact_provider_bind(obj); + linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); + } } return obj; } diff --git a/coreapi/ldap/ldapprovider.h b/coreapi/ldap/ldapprovider.h index bea77554b..be8c23235 100644 --- a/coreapi/ldap/ldapprovider.h +++ b/coreapi/ldap/ldapprovider.h @@ -39,4 +39,4 @@ LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPConta BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider,LinphoneContactProvider) BELLE_SIP_DECLARE_CUSTOM_VPTR_END -LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc); +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f52283cb6..7cc9ee14d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6270,24 +6270,3 @@ void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){ linphone_core_message_storage_init(lc); } } - - -LinphoneContactSearch* linphone_core_ldap_launch_search(LinphoneCore* lc, const char* predicate, ContactSearchCallback cb, void* userdata) -{ - if( lc->ldap ){ - LinphoneContactProvider* cp = LINPHONE_CONTACT_PROVIDER(lc->ldap); - LinphoneContactSearch* search = BELLE_SIP_OBJECT_VPTR(cp,LinphoneContactProvider)->begin_search(cp, predicate, cb, userdata); - char *desc = belle_sip_object_to_string(cp); - - if( desc) { - ms_message("ldap: %s", desc); - ms_free(desc); - } - - if(search){ - belle_sip_object_ref(search); - return search; - } - } - return NULL; -} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 9f57d1ce3..0345344cb 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2216,8 +2216,6 @@ typedef struct _LinphoneContactSearch LinphoneContactSearch; typedef void (*ContactSearchCallback)( LinphoneContactSearch* id, MSList* friends, void* data ); -LINPHONE_PUBLIC LinphoneContactSearch* linphone_core_ldap_launch_search(LinphoneCore* lc, const char* predicate, ContactSearchCallback cb, void* userdata); - #ifdef __cplusplus } #endif diff --git a/gtk/linphone.h b/gtk/linphone.h index 2b2eba531..da398d9df 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -28,6 +28,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "linphonecore.h" +#ifdef BUILD_LDAP +#include "ldap/ldapprovider.h" +#endif + + #ifdef ENABLE_NLS # include # undef _ @@ -68,6 +73,7 @@ void linphone_gtk_show_assistant(void); void linphone_gtk_close_assistant(void); LinphoneCore *linphone_gtk_get_core(void); +LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); GtkWidget *linphone_gtk_get_main_window(); void linphone_gtk_display_something(GtkMessageType type,const gchar *message); void linphone_gtk_start_call(GtkWidget *button); diff --git a/gtk/main.c b/gtk/main.c index 870c1d40e..aa114644d 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -50,6 +50,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION; static LinphoneCore *the_core=NULL; +static LinphoneLDAPContactProvider* ldap_provider = NULL; static GtkWidget *the_ui=NULL; static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg); @@ -256,7 +257,17 @@ 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); - + + +#ifdef BUILD_LDAP + if( lp_config_has_section(linphone_core_get_config(the_core),"ldap") ){ + LpConfig* cfg = linphone_core_get_config(the_core); + LinphoneDictionary* ldap_cfg = lp_config_section_to_dict(cfg, "ldap"); + ldap_provider = linphone_ldap_contact_provider_create(the_core, ldap_cfg); + belle_sip_object_ref( ldap_provider ); + } +#endif + 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); @@ -274,12 +285,20 @@ LinphoneCore *linphone_gtk_get_core(void){ return the_core; } +LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ +#ifdef BUILD_LDAP + return ldap_provider; +#else + return NULL; +#endif +} + GtkWidget *linphone_gtk_get_main_window(){ return the_ui; } void linphone_gtk_destroy_main_window() { - linphone_gtk_destroy_window(the_ui); + linphone_gtk_destroy_window(the_ui); the_ui = NULL; } @@ -786,19 +805,37 @@ struct CompletionTimeout { static gboolean launch_contact_provider_search(void *userdata) { - LinphoneCore* core = linphone_gtk_get_core(); + LinphoneLDAPContactProvider* ldap = linphone_gtk_get_ldap(); GtkWidget* uribar = GTK_WIDGET(userdata); const gchar* predicate = gtk_entry_get_text((GtkEntry*)uribar); - if( strlen(predicate) >= 3 ){ // don't search too small predicates + if( ldap && strlen(predicate) >= 3 ){ // don't search too small predicates + ms_message("launch_contact_provider_search"); - linphone_core_ldap_launch_search(core, predicate, on_contact_provider_search_results, uribar); + + LinphoneContactSearch* search = + BELLE_SIP_OBJECT_VPTR(ldap,LinphoneContactProvider)->begin_search( + LINPHONE_CONTACT_PROVIDER(ldap), + predicate, + on_contact_provider_search_results, + uribar); + + char *desc = belle_sip_object_to_string(ldap); + + if( desc) { + ms_message("ldap: %s", desc); + ms_free(desc); + } + + if(search) + belle_sip_object_ref(search); } return FALSE; } void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) { +#ifdef BUILD_LDAP gchar* text = gtk_editable_get_chars(uribar, 0,-1); gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout")); ms_message("URIBAR changed, new text: %s, userdata %p uribar @%p", text, user_data, uribar); From e5078f6fe2fa2082b51bfda22900c53311479e00 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 6 Dec 2013 14:42:37 +0100 Subject: [PATCH 024/439] Fix compilation issues --- coreapi/linphonecore.c | 5 ----- gtk/main.c | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7cc9ee14d..dee9574fc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1351,11 +1351,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); #endif -#ifdef BUILD_LDAP - lc->ldap =linphone_ldap_contact_provider_create(lc); - belle_sip_object_ref( lc->ldap ); -#endif - if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; diff --git a/gtk/main.c b/gtk/main.c index aa114644d..f7eec5676 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -848,6 +848,7 @@ void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar); gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) ); +#endif } bool_t linphone_gtk_video_enabled(void){ From 7eeff24b34d1befbe046f79e079ed46dc05bbd77 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 6 Dec 2013 18:22:03 +0100 Subject: [PATCH 025/439] 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 f47bee4124c71f0803ffd87fdd3d64d25ee1ecfb Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 12:19:13 +0100 Subject: [PATCH 026/439] 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 79fdfe0f99c674cb160db921823f9a73e576f587 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 12:26:49 +0100 Subject: [PATCH 027/439] 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 b3ed132d05a8213973547830ca8da621fac060c0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 13:19:46 +0100 Subject: [PATCH 028/439] 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 dee9574fc..dfbe77a0d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3088,8 +3088,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 933bca104..671ae742c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -345,7 +345,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 6dbc4512a8dac4a6496d11e42832112fe5ce2797 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Dec 2013 14:01:02 +0100 Subject: [PATCH 029/439] 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 dfbe77a0d..4b387b9d2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2418,18 +2418,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 cc62b5183ea60772eb6876b6d39f0422a7903ca6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Dec 2013 10:50:09 +0100 Subject: [PATCH 030/439] Include patch from linphone web version. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 19087a244..6eaec1cb6 100644 --- a/configure.ac +++ b/configure.ac @@ -36,7 +36,7 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AC_SUBST([docdir], [${datadir}/doc]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) -dnl don't put anythingelse before AC_PROG_CC unless checking if macro still work for clang +gl_LD_OUTPUT_DEF AC_PROG_CXX(["xcrun clang++" g++]) AC_PROG_CC(["xcrun clang" gcc]) From 38a08cb7deff2e6b91673f7eb956f5a137bb2563 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 12:39:36 +0100 Subject: [PATCH 031/439] fix call tester to use file instead of capture card for callee --- tester/call_tester.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index b166cb86e..5efd2d152 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1035,8 +1035,7 @@ static void early_media_call_forking(void) { LinphoneCall *marie2_call; LinphoneCall *pauline_call; int dummy=0; - char ringbackpath[256]; - snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); + char hellopath[256]; pol.automatically_accept=1; pol.automatically_initiate=1; @@ -1049,10 +1048,11 @@ 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); - linphone_core_set_play_file(marie1->lc,ringbackpath); - + 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 7642b8c5bb22c1811da0b6b4910c35f44f8b5173 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 14:07:06 +0100 Subject: [PATCH 032/439] fix early media call forking to avoid capture card sharing between parties --- tester/call_tester.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 5efd2d152..615886606 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1035,7 +1035,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; @@ -1048,12 +1049,10 @@ 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); From 924c9381a923ea4cacbd3ecba4af436f794e2a9f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 4 Dec 2013 22:04:33 +0100 Subject: [PATCH 033/439] fix clang detection, MS2:fix upnp version detection with clang --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6eaec1cb6..19087a244 100644 --- a/configure.ac +++ b/configure.ac @@ -36,7 +36,7 @@ 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]) From a2668179410ee61b4bf345e3df3ac07498883fd9 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 6 Dec 2013 14:34:59 +0100 Subject: [PATCH 034/439] Added LDAP configuration tab in UI --- gtk/parameters.ui | 519 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 519 insertions(+) diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 4cb435eb2..99f0cb268 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -9,6 +9,12 @@ 1 10

+ + 500 + 50 + 1 + 10 + 1 65535 @@ -54,6 +60,12 @@ 1 10 + + 100 + 10 + 1 + 10 + 65535 2 @@ -81,6 +93,23 @@ 10 + + + + + + + + anonymous + + + GSSAPI + + + SASL + + + @@ -2428,6 +2457,496 @@ False + + + True + False + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + 2 + + + True + False + 1 + Server address: + + + + + True + False + Authentication method: + + + 1 + 2 + + + + + True + False + Username: + + + 2 + 3 + + + + + True + False + Password: + + + 3 + 4 + + + + + Use TLS Connection + True + True + False + False + True + + + 1 + 2 + 4 + 5 + + + + + True + True + + False + False + True + True + + + 1 + 2 + + + + + True + True + + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 3 + 4 + + + + + + + + True + False + liststore2 + 0 + 0 + 0 + + + + 0 + + + + + 1 + 2 + 1 + 2 + + + + + + + + + True + False + <b>Connection</b> + True + + + + + True + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + 2 + + + True + False + Base object: + + + + + True + False + Filter (%s for name): + + + 1 + 2 + + + + + True + False + Name Attribute: + + + 2 + 3 + + + + + True + False + SIP address attribute: + + + 3 + 4 + + + + + True + False + Attributes to query: + + + 4 + 5 + + + + + True + True + + False + False + True + True + + + 1 + 2 + + + + + True + True + + False + False + True + True + + + 1 + 2 + 1 + 2 + + + + + True + True + + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + True + True + + False + False + True + True + + + 1 + 2 + 3 + 4 + + + + + True + True + + False + False + True + True + + + 1 + 2 + 4 + 5 + + + + + + + + + True + False + <b>Search</b> + True + + + + + True + True + 1 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 3 + 2 + + + True + False + Timeout for search: + + + + + True + False + Max results: + + + 1 + 2 + + + + + True + True + + False + False + True + True + adjustment9 + + + 1 + 2 + + + + + True + True + 3 + + False + False + True + True + adjustment10 + True + + + 1 + 2 + 1 + 2 + + + + + Follow Aliases + True + True + False + False + True + + + 1 + 2 + 2 + 3 + + + + + + + + + + + + True + False + <b>Miscellaneous</b> + True + + + + + True + True + 2 + + + + + 5 + + + + + True + False + + + True + False + gtk-disconnect + + + True + True + 0 + + + + + True + False + LDAP + + + True + True + 1 + + + + + 5 + False + + True From f8134446ac4747f45fa9e2d759b7f21e414e8785 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 9 Dec 2013 11:52:52 +0100 Subject: [PATCH 035/439] Add BELLESIP_CFLAGS and BELLESIP_LIBS to various Makefile.am --- console/Makefile.am | 5 +++-- gtk/Makefile.am | 4 ++-- tester/Makefile.am | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/console/Makefile.am b/console/Makefile.am index 84e0c94cd..3a975e9c4 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -24,11 +24,12 @@ bin_PROGRAMS+=linphoned endif linphonec_SOURCES=linphonec.c linphonec.h commands.c -linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) +linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) $(BELLESIP_CFLAGS) linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la \ $(READLINE_LIBS) \ $(SQLITE3_LIBS) \ - $(X11_LIBS) + $(X11_LIBS) \ + $(BELLESIP_LIBS) if BUILD_WIN32 #special build of linphonec to detach from the windows console diff --git a/gtk/Makefile.am b/gtk/Makefile.am index b80527de0..2f13d8b49 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -55,7 +55,7 @@ linphone_SOURCES+= \ endif linphone_LDADD= $(top_builddir)/coreapi/liblinphone.la \ - $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) $(SQLITE3_LIBS) + $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) $(SQLITE3_LIBS) $(BELLESIP_LIBS) if BUILD_WIN32 @@ -77,7 +77,7 @@ endif AM_CFLAGS= -DIN_LINPHONE -I$(top_srcdir)/coreapi/ \ $(MEDIASTREAMER_CFLAGS) \ - $(ORTP_CFLAGS) \ + $(ORTP_CFLAGS) $(BELLESIP_CFLAGS) \ $(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) $(IPV6_CFLAGS) \ $(TUNNEL_CFLAGS) \ $(SQLITE3_CFLAGS) diff --git a/tester/Makefile.am b/tester/Makefile.am index e81c85d97..4388ac483 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -23,11 +23,11 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi -LDADD=$(top_builddir)/coreapi/liblinphone.la +LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) AM_LDFLAGS=$(CUNIT_LIBS) -AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) +AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) test: liblinphone_tester ./liblinphone_tester --config $(abs_srcdir) From 50b84cf73a9dcf997175f2c170727033acbb0dca Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 9 Dec 2013 11:57:15 +0100 Subject: [PATCH 036/439] Working version of the LDAP configuration panel in GTK. --- coreapi/dict.c | 2 +- coreapi/ldap/ldapprovider.c | 33 +++++---- coreapi/linphonecore.h | 2 +- gtk/linphone.h | 1 + gtk/main.c | 27 +++++--- gtk/parameters.ui | 56 +++++++++++++-- gtk/propertybox.c | 135 ++++++++++++++++++++++++++++++++++++ 7 files changed, 223 insertions(+), 33 deletions(-) diff --git a/coreapi/dict.c b/coreapi/dict.c index 69b2bb4ee..4535e1a27 100644 --- a/coreapi/dict.c +++ b/coreapi/dict.c @@ -96,7 +96,7 @@ void linphone_dictionary_clear(LinphoneDictionary* obj) belle_sip_dict_clear(obj); } -int linphone_dictionary_haskey(LinphoneDictionary* obj, const char* key) +int linphone_dictionary_haskey(const LinphoneDictionary* obj, const char* key) { return belle_sip_dict_haskey(obj, key); } diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 3bab710b2..ec7c2f57d 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -53,16 +53,17 @@ struct _LinphoneLDAPContactProvider // config int use_tls; LDAPAuthMethod auth_method; - char* username; - char* password; - char* server; + const char* username; + const char* password; + const char* server; - char* base_object; - char** attributes; - char* sip_attr; - char* name_attr; + const char* base_object; + const char* sip_attr; + const char* name_attr; + const char* filter; + + char** attributes; - char* filter; int timeout; int deref_aliases; int max_results; @@ -150,6 +151,7 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch, static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ); static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req); static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); +static bool_t linphone_ldap_contact_provider_iterate(void *data); /* Authentication methods */ struct AuthMethodDescription{ @@ -182,6 +184,9 @@ static void linphone_ldap_contact_provider_destroy_request_cb(void *req) static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) { + ms_message("linphone_ldap_contact_provider_destroy"); + linphone_core_remove_iterate_hook(LINPHONE_CONTACT_PROVIDER(obj)->lc, linphone_ldap_contact_provider_iterate,obj); + // clean pending requests ms_list_for_each(obj->requests, linphone_ldap_contact_provider_destroy_request_cb); @@ -399,7 +404,7 @@ static char* required_config_keys[] = { NULL }; -static bool_t linphone_ldap_contact_provider_valid_config(LinphoneDictionary* dict) +static bool_t linphone_ldap_contact_provider_valid_config(const LinphoneDictionary* dict) { char** config_name = required_config_keys; @@ -410,6 +415,7 @@ static bool_t linphone_ldap_contact_provider_valid_config(LinphoneDictionary* di has_key = linphone_dictionary_haskey(dict, *config_name); if( !has_key ) ms_error("Missing LDAP config value for '%s'", *config_name); valid &= has_key; + config_name++; } return valid; } @@ -426,9 +432,7 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide if( obj->config ) linphone_dictionary_unref(obj->config); // clone new config into the dictionary - obj->config = linphone_dictionary_clone(dict); - linphone_dictionary_ref(obj->config); - + obj->config = linphone_dictionary_ref(linphone_dictionary_clone(dict)); obj->use_tls = linphone_dictionary_get_int(obj->config, "use_tls", 0); obj->timeout = linphone_dictionary_get_int(obj->config, "timeout", 10); @@ -480,8 +484,7 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) { - const char* password_str = linphone_dictionary_get_string(obj, "password", ""); - struct berval password = { strlen( password_str ), password_str }; + struct berval password = { strlen( obj->password ), ms_strdup(obj->password) }; int ret; int bind_msgid = 0; @@ -505,6 +508,8 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj break; } } + if(password.bv_val) ms_free(password.bv_val); + return 0; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 0345344cb..479163397 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -200,7 +200,7 @@ LINPHONE_PUBLIC void linphone_dictionary_set_int64(LinphoneDictionary* obj, cons LINPHONE_PUBLIC int64_t linphone_dictionary_get_int64(LinphoneDictionary* obj, const char* key, int64_t default_value); LINPHONE_PUBLIC int linphone_dictionary_remove(LinphoneDictionary* obj, const char* key); LINPHONE_PUBLIC void linphone_dictionary_clear(LinphoneDictionary* obj); -LINPHONE_PUBLIC int linphone_dictionary_haskey(LinphoneDictionary* obj, const char* key); +LINPHONE_PUBLIC int linphone_dictionary_haskey(const LinphoneDictionary* obj, const char* key); LINPHONE_PUBLIC void linphone_dictionary_foreach( const LinphoneDictionary* obj, void (*apply_func)(const char*key, void* value, void* userdata), void* userdata); /** * Converts a config section into a dictionary. diff --git a/gtk/linphone.h b/gtk/linphone.h index da398d9df..c77a02e6d 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -74,6 +74,7 @@ void linphone_gtk_close_assistant(void); LinphoneCore *linphone_gtk_get_core(void); LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); +void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap); GtkWidget *linphone_gtk_get_main_window(); void linphone_gtk_display_something(GtkMessageType type,const gchar *message); void linphone_gtk_start_call(GtkWidget *button); diff --git a/gtk/main.c b/gtk/main.c index f7eec5676..5dde19199 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -232,6 +232,22 @@ static const char *linphone_gtk_get_factory_config_file(){ return _factory_config_file; } +LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ +#ifdef BUILD_LDAP + return ldap_provider; +#else + return NULL; +#endif +} + +void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) +{ + if( ldap_provider ) + belle_sip_object_unref(ldap_provider); + + ldap_provider = LINPHONE_LDAP_CONTACT_PROVIDER(belle_sip_object_ref( ldap )); +} + static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file, const char *db_file) { LinphoneCoreVTable vtable={0}; @@ -263,8 +279,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, if( lp_config_has_section(linphone_core_get_config(the_core),"ldap") ){ LpConfig* cfg = linphone_core_get_config(the_core); LinphoneDictionary* ldap_cfg = lp_config_section_to_dict(cfg, "ldap"); - ldap_provider = linphone_ldap_contact_provider_create(the_core, ldap_cfg); - belle_sip_object_ref( ldap_provider ); + linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(the_core, ldap_cfg) ); } #endif @@ -285,14 +300,6 @@ LinphoneCore *linphone_gtk_get_core(void){ return the_core; } -LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ -#ifdef BUILD_LDAP - return ldap_provider; -#else - return NULL; -#endif -} - GtkWidget *linphone_gtk_get_main_window(){ return the_ui; } diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 99f0cb268..9a42760b8 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -2520,7 +2520,7 @@ - + Use TLS Connection True True @@ -2536,7 +2536,7 @@ - + True True @@ -2585,9 +2585,6 @@ 4 - - - True @@ -2851,7 +2848,7 @@ - + True True 3 @@ -2871,7 +2868,7 @@ - + Follow Aliases True True @@ -2908,6 +2905,51 @@ 2 + + + True + False + 2 + + + + + + Reset + True + True + True + False + + + + False + False + 1 + + + + + Save + True + True + True + False + + + + False + False + 2 + + + + + False + True + 3 + + 5 diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 8579fc2f4..20c0b01cd 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone.h" #include "linphone_tunnel.h" +#include "lpconfig.h" typedef enum { CAP_IGNORE, @@ -59,6 +60,131 @@ static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); } +static void linphone_gtk_ldap_load_settings(GtkWidget* param) +{ + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + LpConfig* config = linphone_core_get_config(linphone_gtk_get_core()); + LinphoneDictionary* ldap_conf = lp_config_section_to_dict(config,"ldap"); + GtkEntry* entry; + GtkToggleButton* toggle; + GtkSpinButton* spin; + + + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_use_tls")); + gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"use_tls", 0) ); + + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_server")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://example.com") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_username")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"username", "") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_password")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"password", "") ); + + // TODO + // GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"ldap_auth_method")); + // gtk_combo_box_set_active(entry, linphone_dictionary_get_string(ldap_conf,"auth_method", "anonymous") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_base_object")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"base_object", "dc=example,dc=com") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_filter")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"filter", "uid=*%s*") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_name_attribute")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"name_attribute", "cn") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_sip_attribute")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sip_attribute", "mobile") ); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_attributes")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"attributes", "cn,givenName,sn,mobile,homePhone") ); + + + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_deref_aliases")); + gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"deref_aliases", 0) ); + + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_max_results")); + gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"max_results", 50) ); + + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_timeout")); + gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"timeout", 10) ); + +} + +void linphone_gtk_ldap_reset(GtkWidget *tabmgr) +{ + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + ms_message("RESET LDAP"); + linphone_gtk_ldap_load_settings(pb); +} + +void linphone_gtk_ldap_save(GtkWidget *tabmgr) +{ + LinphoneCore *lc = linphone_gtk_get_core(); + LpConfig* conf = linphone_core_get_config(lc); + LinphoneDictionary* dict = linphone_dictionary_new(); + + GtkWidget *mw = linphone_gtk_get_main_window(); + GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + GtkEntry* entry; + GtkToggleButton* toggle; + GtkSpinButton* spin; + + ms_message("SAVE LDAP"); + + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_use_tls")); + linphone_dictionary_set_int(dict, "use_tls", gtk_toggle_button_get_active(toggle)); + + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_server")); + linphone_dictionary_set_string(dict, "server", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_username")); + linphone_dictionary_set_string(dict, "username", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_password")); + linphone_dictionary_set_string(dict, "password", gtk_entry_get_text(entry)); + + + GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"ldap_auth_method")); + linphone_dictionary_set_string(dict, "auth_method", gtk_combo_box_get_active_text(cbox)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_base_object")); + linphone_dictionary_set_string(dict, "base_object", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_filter")); + linphone_dictionary_set_string(dict, "filter", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_name_attribute")); + linphone_dictionary_set_string(dict, "name_attribute", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_sip_attribute")); + linphone_dictionary_set_string(dict, "sip_attribute", gtk_entry_get_text(entry)); + + entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_attributes")); + linphone_dictionary_set_string(dict, "attributes", gtk_entry_get_text(entry)); + + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_deref_aliases")); + linphone_dictionary_set_int(dict, "deref_aliases", gtk_toggle_button_get_active(toggle)); + + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_max_results")); + linphone_dictionary_set_int(dict, "max_results", gtk_spin_button_get_value(spin) ); + + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_timeout")); + linphone_dictionary_set_int(dict, "timeout", gtk_spin_button_get_value(spin) ); + + ms_message("Create LDAP from config"); + // create new LDAP according to the validated config + linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(lc, dict) ); + // save the config to linphonerc: + lp_config_load_dict_to_section(conf, "ldap", dict); +} + void linphone_gtk_fill_video_sizes(GtkWidget *combo){ const MSVideoSizeDef *def=linphone_core_get_supported_video_sizes(linphone_gtk_get_core());; int i,active=0; @@ -1301,6 +1427,15 @@ void linphone_gtk_show_parameters(void){ gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_label")), TRUE); } + /* LDAP CONFIG */ +#ifdef BUILD_LDAP + linphone_gtk_ldap_load_settings(pb); +#else + // hide the LDAP tab + GtkNotebook* notebook = GTK_NOTEBOOK(linphone_gtk_get_widget(pb, "notebook1")); + gtk_notebook_remove_page(notebook,5); +#endif + gtk_widget_show(pb); } From 79d3a8d1a2bed096f23af664e7eba3da109330b5 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 9 Dec 2013 12:41:58 +0100 Subject: [PATCH 037/439] Some renaming and trace removal. --- coreapi/ldap/ldapprovider.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index ec7c2f57d..b5ded2ae3 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -148,7 +148,8 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch, /* *************************** * LinphoneLDAPContactProvider * ***************************/ -static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ); + +static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_search( LinphoneLDAPContactProvider* obj, int msgid ); static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req); static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); static bool_t linphone_ldap_contact_provider_iterate(void *data); @@ -247,7 +248,7 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon if( dn ){ - ms_message("search result: dn: %s", dn); + //ms_message("search result: dn: %s", dn); ldap_memfree(dn); } @@ -346,9 +347,9 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) case LDAP_RES_SEARCH_RESULT: { LDAPMessage* message = ldap_first_message(obj->ld, results); - LinphoneLDAPContactSearch* req = linphone_ldap_request_entry_search(obj, ldap_msgid(message)); + LinphoneLDAPContactSearch* req = linphone_ldap_contact_provider_request_search(obj, ldap_msgid(message)); while( message != NULL ){ - ms_message("Message @%p:id %d / type %x / associated request: %p", message, ldap_msgid(message), ldap_msgtype(message), req); + //ms_message("Message @%p:id %d / type %x / associated request: %p", message, ldap_msgid(message), ldap_msgtype(message), req); linphone_ldap_contact_provider_handle_search_result(obj, req, message ); message = ldap_next_message(obj->ld, message); } @@ -541,7 +542,7 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* obj = NULL; } else { // register our hook into iterate so that LDAP can do its magic asynchronously. - linphone_ldap_contact_provider_bind(obj); + //linphone_ldap_contact_provider_bind(obj); linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); } } @@ -570,7 +571,7 @@ static int linphone_ldap_request_entry_compare_strong(const void*a, const void* return !(ra->msgid == rb->msgid) && !(ra == rb); } -static inline LinphoneLDAPContactSearch* linphone_ldap_request_entry_search( LinphoneLDAPContactProvider* obj, int msgid ) +static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_search( LinphoneLDAPContactProvider* obj, int msgid ) { LinphoneLDAPContactSearch dummy = {}; dummy.msgid = msgid; @@ -598,11 +599,15 @@ static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContact return ret; } -static LinphoneLDAPContactSearch* linphone_ldap_begin_search ( LinphoneLDAPContactProvider* obj, +static LinphoneLDAPContactSearch* linphone_ldap_contact_provider_begin_search ( LinphoneLDAPContactProvider* obj, const char* predicate, ContactSearchCallback cb, void* cb_data ) { + // if we're not yet connected, bind + if( !obj->connected ) linphone_ldap_contact_provider_bind(obj); + + LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create ( obj, predicate, cb, cb_data ); if ( request != NULL ) { @@ -615,7 +620,7 @@ static LinphoneLDAPContactSearch* linphone_ldap_begin_search ( LinphoneLDAPConta } -static int linphone_ldap_marshal(LinphoneLDAPContactProvider* obj, char* buff, size_t buff_size, size_t *offset) +static int linphone_ldap_contact_provider_marshal(LinphoneLDAPContactProvider* obj, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error = BELLE_SIP_OK; @@ -672,10 +677,10 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE), (belle_sip_object_destroy_t)linphone_ldap_contact_provider_destroy, NULL, - (belle_sip_object_marshal_t)linphone_ldap_marshal + (belle_sip_object_marshal_t)linphone_ldap_contact_provider_marshal }, "LDAP", - (LinphoneContactProviderStartSearchMethod)linphone_ldap_begin_search, + (LinphoneContactProviderStartSearchMethod)linphone_ldap_contact_provider_begin_search, (LinphoneContactProviderCancelSearchMethod)linphone_ldap_contact_provider_cancel_search } }; From 963f650912618246af14cb4f9f972e23043c0c36 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 9 Dec 2013 12:43:58 +0100 Subject: [PATCH 038/439] LDAP search optimization: don't relaunch narrower search if results are alreay here. + fix alignment of buttons in UI --- gtk/main.c | 24 +++++++++++++----------- gtk/parameters.ui | 32 +++++++++++++++++--------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index 5dde19199..a1a9e2429 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -814,12 +814,22 @@ static gboolean launch_contact_provider_search(void *userdata) { LinphoneLDAPContactProvider* ldap = linphone_gtk_get_ldap(); GtkWidget* uribar = GTK_WIDGET(userdata); - const gchar* predicate = gtk_entry_get_text((GtkEntry*)uribar); + const gchar* predicate = gtk_entry_get_text(GTK_ENTRY(uribar)); + gchar* previous_search = gtk_object_get_data(GTK_OBJECT(uribar), "previous_search"); if( ldap && strlen(predicate) >= 3 ){ // don't search too small predicates - ms_message("launch_contact_provider_search"); + if( previous_search && (strstr(predicate, previous_search) == predicate) ){ + ms_message("Don't launch search on already searched data (current: %s, old search: %s)", + predicate, previous_search); + return FALSE; + } + // save current search + if( previous_search ) ms_free(previous_search); + gtk_object_set_data(GTK_OBJECT(uribar), "previous_search", ms_strdup(predicate)); + + ms_message("launch_contact_provider_search"); LinphoneContactSearch* search = BELLE_SIP_OBJECT_VPTR(ldap,LinphoneContactProvider)->begin_search( LINPHONE_CONTACT_PROVIDER(ldap), @@ -827,13 +837,6 @@ static gboolean launch_contact_provider_search(void *userdata) on_contact_provider_search_results, uribar); - char *desc = belle_sip_object_to_string(ldap); - - if( desc) { - ms_message("ldap: %s", desc); - ms_free(desc); - } - if(search) belle_sip_object_ref(search); } @@ -845,13 +848,12 @@ void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) #ifdef BUILD_LDAP gchar* text = gtk_editable_get_chars(uribar, 0,-1); gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout")); - ms_message("URIBAR changed, new text: %s, userdata %p uribar @%p", text, user_data, uribar); if( text ) g_free(text); - if( timeout != 0 ) { g_source_remove(timeout); } + timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar); gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) ); diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 9a42760b8..21464d9e4 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -2913,21 +2913,6 @@ - - - Reset - True - True - True - False - - - - False - False - 1 - - Save @@ -2940,6 +2925,23 @@ False False + end + 1 + + + + + Reset + True + True + True + False + + + + False + False + end 2 From 2c98560c57b6ea6cdfd937cb8306784b73a38cab Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 9 Dec 2013 13:53:33 +0100 Subject: [PATCH 039/439] - Relaunch search if last search returned max_results, since we could have truncated the result list - Remove the contact provider when exiting. --- coreapi/ldap/ldapprovider.c | 13 ++++++++++++- coreapi/ldap/ldapprovider.h | 3 +++ gtk/main.c | 23 +++++++++++++++++++---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index b5ded2ae3..3fcc1a3dd 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -77,7 +77,7 @@ struct _LinphoneLDAPContactSearch char* filter; bool_t complete; MSList* found_entries; - int found_count; + unsigned int found_count; }; @@ -128,6 +128,12 @@ void linphone_ldap_contact_search_destroy_friend( void* entry ) linphone_friend_destroy((LinphoneFriend*)entry); } +unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj) +{ + return obj->found_count; +} + + static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj ) { ms_message("~LinphoneLDAPContactSearch(%p)", obj); @@ -514,6 +520,11 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj return 0; } +unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj) +{ + return obj->max_results; +} + LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config) { LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider); diff --git a/coreapi/ldap/ldapprovider.h b/coreapi/ldap/ldapprovider.h index be8c23235..73878ee7c 100644 --- a/coreapi/ldap/ldapprovider.h +++ b/coreapi/ldap/ldapprovider.h @@ -31,6 +31,8 @@ LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPConta ContactSearchCallback cb, void* cb_data); +unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj); + /* LinphoneLDAPContactProvider */ @@ -40,3 +42,4 @@ BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider,LinphoneContactP BELLE_SIP_DECLARE_CUSTOM_VPTR_END LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config); +unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj); diff --git a/gtk/main.c b/gtk/main.c index a1a9e2429..d9b86a4b4 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -245,7 +245,8 @@ void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) if( ldap_provider ) belle_sip_object_unref(ldap_provider); - ldap_provider = LINPHONE_LDAP_CONTACT_PROVIDER(belle_sip_object_ref( ldap )); + ldap_provider = ldap ? LINPHONE_LDAP_CONTACT_PROVIDER(belle_sip_object_ref( ldap )) + : NULL; } static void linphone_gtk_init_liblinphone(const char *config_file, @@ -798,6 +799,12 @@ void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* fri friends = friends->next; } gtk_entry_completion_complete(compl); + // save the number of LDAP results to better decide if new results should be fetched when search predicate gets bigger + gtk_object_set_data(GTK_OBJECT(uribar), "ldap_res_cout", + GINT_TO_POINTER( + linphone_ldap_contact_search_result_count(LINPHONE_LDAP_CONTACT_SEARCH(req)) + ) + ); // Gtk bug? we need to emit a "changed" signal so that the completion appears if // the list of results was previously empty @@ -816,12 +823,17 @@ static gboolean launch_contact_provider_search(void *userdata) GtkWidget* uribar = GTK_WIDGET(userdata); const gchar* predicate = gtk_entry_get_text(GTK_ENTRY(uribar)); gchar* previous_search = gtk_object_get_data(GTK_OBJECT(uribar), "previous_search"); + unsigned int prev_res_count = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "ldap_res_cout")); if( ldap && strlen(predicate) >= 3 ){ // don't search too small predicates + unsigned int max_res_count = linphone_ldap_contact_provider_get_max_result(ldap); - if( previous_search && (strstr(predicate, previous_search) == predicate) ){ - ms_message("Don't launch search on already searched data (current: %s, old search: %s)", - predicate, previous_search); + if( previous_search && + (strstr(predicate, previous_search) == predicate) && // last search contained results from this one + (prev_res_count != max_res_count) ){ // and we didn't reach the max result limit + + ms_message("Don't launch search on already searched data (current: %s, old search: %s), (%d/%d results)", + predicate, previous_search, prev_res_count, max_res_count); return FALSE; } @@ -2032,6 +2044,9 @@ static void linphone_gtk_quit(void){ g_source_remove_by_user_data(linphone_gtk_get_core()); #ifdef BUILD_WIZARD linphone_gtk_close_assistant(); +#endif +#ifdef BUILD_LDAP + linphone_gtk_set_ldap(NULL); #endif linphone_gtk_uninit_instance(); linphone_gtk_destroy_log_window(); From 198d41812b2d012c2403a513802b87f35f8d7d64 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 9 Dec 2013 14:14:23 +0100 Subject: [PATCH 040/439] Fix leak --- coreapi/ldap/ldapprovider.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 3fcc1a3dd..1e2b942b6 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -291,6 +291,7 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon ms_message("Added friend %s / %s", ldap_data.name, ldap_data.sip); ms_free(ldap_data.sip); ms_free(ldap_data.name); + linphone_address_destroy(la); } } From e9ad2787d158422ecbca122ecce975bc2f036c70 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Dec 2013 17:07:44 +0100 Subject: [PATCH 041/439] Free memory allocated by belle_sip_malloc() with belle_sip_free(). --- coreapi/bellesip_sal/sal_op_presence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index bdc58388b..2e6ea3fcd 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -28,7 +28,7 @@ void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceMo belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(notify,belle_sip_header_from_t); contact_info=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); op->base.root->callbacks.convert_presence_to_xml_requested(op, presence, contact_info, &content); - ms_free(contact_info); + belle_sip_free(contact_info); if (content == NULL) return; } From 6b263466e0ecf411f1100fa4a9f3ad443a2249c7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 10 Dec 2013 21:45:44 +0100 Subject: [PATCH 042/439] fix another alloc/free mismatch (required for windows) --- NEWS | 14 ++++++++++++-- coreapi/bellesip_sal/sal_impl.c | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 8797315b0..872a678fa 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,15 @@ linphone-3.7...?? - Liblinphone level improvements thanks to belle-sip new SIP stack: - * multiple SIP transports simualtaneously now allowed + Application level improvements: + * It is now possible to configure multiple proxy accounts with different transports (UDP, TCP, TLS) + * can work with IPv6 and IPv4 simultaneously + * User can choose video rendering method on Linux + * Video HD formats support added, leveraging on multiple cores for encoding if available + * Keyboard can be used for DTMF input + * Faster and higly responsive UI thanks to fully asynchronous operation of the liblinphone. + * Addon of opus codec + + Liblinphone level improvements thanks to new "belle-sip" SIP stack: + * multiple SIP transports simultaneously now allowed * IP dual stack: can use IPv6 and IPv4 simultaneously * fully asynchronous behavior: no more lengthly DNS or connections * +sip.instance parameter (RFC5626) @@ -10,6 +19,7 @@ linphone-3.7...?? * SIP transaction state machines improved (RFC6026) * Privacy API (RFC3323, RFC3325) * Full support of rich presence in (RFC4480) + * Better handling of sips scheme in URIs. linphone-3.6.1 -- June 17, 2013 diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 37384f3e9..08986eb89 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -810,11 +810,11 @@ const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op){ void sal_set_uuid(Sal *sal, const char *uuid){ if (sal->uuid){ - belle_sip_free(sal->uuid); + ms_free(sal->uuid); sal->uuid=NULL; } if (uuid) - sal->uuid=belle_sip_strdup(uuid); + sal->uuid=ms_strdup(uuid); } typedef struct { From 5f28f81f4b3afa0bcbab2f2aa920f830acfb4b2a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 11 Dec 2013 16:17:02 +0100 Subject: [PATCH 043/439] fix LinphoneProxyConfig.getError() jni --- coreapi/linphonecore_jni.cc | 1 + java/impl/org/linphone/core/LinphoneProxyConfigImpl.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 65438fc19..9840cc6b1 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1435,6 +1435,7 @@ extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_edit(JNIEnv* env, extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_done(JNIEnv* env,jobject thiz,jlong proxyCfg) { linphone_proxy_config_done((LinphoneProxyConfig*)proxyCfg); } + extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_normalizePhoneNumber(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jnumber) { if (jnumber == 0) { ms_error("cannot normalized null number"); diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index dfa9c5170..2b304c8c1 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -171,10 +171,10 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public int lookupCCCFromE164(String e164) { return lookupCCCFromE164(nativePtr, e164); } - private native int getReason(long nativeptr); + private native int getError(long nativeptr); @Override public Reason getError() { - return Reason.fromInt(getReason(nativePtr)); + return Reason.fromInt(getError(nativePtr)); } private native void setPrivacy(long nativePtr, int mask); @Override From c53381e0b5a6ba74c6769eb184d0d981692764a4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 12 Dec 2013 11:07:34 +0100 Subject: [PATCH 044/439] add linphone_proxy_config_set_contact_uri_parameters() --- coreapi/bellesip_sal/sal_address_impl.c | 11 ++++ coreapi/linphonecore.h | 2 + coreapi/private.h | 1 + coreapi/proxy.c | 79 ++++++++++++------------- include/sal/sal.h | 7 +-- 5 files changed, 55 insertions(+), 45 deletions(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 91c2d91c8..26e29b321 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -150,6 +150,17 @@ void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ return ; } + +void sal_address_set_params(SalAddress *addr, const char *params){ + belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr); + belle_sip_parameters_set(parameters,params); +} + +void sal_address_set_uri_params(SalAddress *addr, const char *params){ + belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr))); + belle_sip_parameters_set(parameters,params); +} + void sal_address_set_transport(SalAddress* addr,SalTransport transport){ if (!sal_address_is_secure(addr)){ SAL_ADDRESS_SET(addr,transport_param,sal_transport_to_string(transport)); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b9c9a5030..88e933e32 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -752,6 +752,8 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProx LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj); LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params); +LINPHONE_PUBLIC void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *obj, const char *contact_uri_params); +LINPHONE_PUBLIC const char* linphone_proxy_config_get_contact_uri_parameters(const LinphoneProxyConfig *obj); /** * Get the #LinphoneCore object to which is associated the #LinphoneProxyConfig. diff --git a/coreapi/private.h b/coreapi/private.h index 37ff460ae..b5799632a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -392,6 +392,7 @@ struct _LinphoneProxyConfig char *reg_route; char *realm; char *contact_params; + char *contact_uri_params; int expires; SalOp *op; char *type; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a353d862e..dbc39f58a 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -88,6 +88,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->op) sal_op_release(obj->op); if (obj->publish_op) sal_op_release(obj->publish_op); if (obj->contact_params) ms_free(obj->contact_params); + if (obj->contact_uri_params) ms_free(obj->contact_uri_params); ms_free(obj); } @@ -280,69 +281,37 @@ void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj){ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ LinphoneAddress *ret=NULL; LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); - const char *host; + if (proxy==NULL) return NULL; - host=linphone_address_get_domain (proxy); + host=linphone_address_get_domain(proxy); if (host!=NULL){ int localport = -1; const char *localip = NULL; - char *tmp; - char *tmp2; - LinphoneAddress *identity; - LinphoneAddress *contact; + LinphoneAddress *contact=linphone_address_new(obj->reg_identity); if (obj->contact_params) { // We want to add a list of contacts params to the linphone address - // We remove the display name in the identity (if present) to prevent a failure in the parsing of the address due to the quotes - identity = linphone_address_new(obj->reg_identity); - if (identity) { - tmp2 = linphone_address_as_string_uri_only(identity); - tmp = ms_strdup_printf("%s;%s", tmp2, obj->contact_params); - linphone_address_destroy(identity); - ms_free(tmp2); - } else { - tmp = ms_strdup_printf("%s;%s", obj->reg_identity, obj->contact_params); - } + sal_address_set_params(contact,obj->contact_params); } - else { - tmp = strdup(obj->reg_identity); + if (obj->contact_uri_params){ + sal_address_set_uri_params(contact,obj->contact_uri_params); } - - contact = linphone_address_new(tmp); - if (!contact) { - ms_error("No valid contact_params for [%s]",linphone_address_get_domain(proxy)); - return NULL; - } - #ifdef BUILD_UPNP if (obj->lc->upnp != NULL && linphone_core_get_firewall_policy(obj->lc)==LinphonePolicyUseUpnp && linphone_upnp_context_get_state(obj->lc->upnp) == LinphoneUpnpStateOk) { LCSipTransports tr; localip = linphone_upnp_context_get_external_ipaddress(obj->lc->upnp); localport = linphone_upnp_context_get_external_port(obj->lc->upnp); - linphone_core_get_sip_transports(obj->lc,&tr); - if (tr.udp_port <= 0) { - if (tr.tcp_port>0) { - sal_address_set_param(contact,"transport","tcp"); - } else if (tr.tls_port>0) { - sal_address_set_param(contact,"transport","tls"); - } - } - } #endif //BUILD_UPNP - - linphone_address_set_port(contact,localport); linphone_address_set_domain(contact,localip); linphone_address_set_display_name(contact,NULL); ret=contact; - - linphone_address_destroy (proxy); - ms_free(tmp); } + linphone_address_destroy(proxy); return ret; } @@ -911,7 +880,7 @@ bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj){ * @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else" * * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id. - * As an example, the contact address in the SIP register sent will look like . + * As an example, the contact address in the SIP register sent will look like ;apple-push-id=43143-DFE23F-2323-FA2232. **/ void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params){ if (obj->contact_params) { @@ -923,6 +892,24 @@ void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, cons } } +/** + * Set optional contact parameters that will be added to the contact information sent in the registration, inside the URI. + * @param obj the proxy config object + * @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else" + * + * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id. + * As an example, the contact address in the SIP register sent will look like . +**/ +void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *obj, const char *contact_uri_params){ + if (obj->contact_uri_params) { + ms_free(obj->contact_uri_params); + obj->contact_uri_params=NULL; + } + if (contact_uri_params){ + obj->contact_uri_params=ms_strdup(contact_uri_params); + } +} + /** * Returns previously set contact parameters. **/ @@ -930,6 +917,13 @@ const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConf return obj->contact_params; } +/** + * Returns previously set contact URI parameters. +**/ +const char *linphone_proxy_config_get_contact_uri_parameters(const LinphoneProxyConfig *obj){ + return obj->contact_uri_params; +} + struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj){ return obj->lc; } @@ -1059,6 +1053,9 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC if (obj->contact_params!=NULL){ lp_config_set_string(config,key,"contact_parameters",obj->contact_params); } + if (obj->contact_uri_params!=NULL){ + lp_config_set_string(config,key,"contact_uri_parameters",obj->contact_uri_params); + } lp_config_set_int(config,key,"reg_expires",obj->expires); lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister); lp_config_set_int(config,key,"publish",obj->publish); @@ -1096,6 +1093,8 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); + linphone_proxy_config_set_contact_uri_parameters(cfg,lp_config_get_string(config,key,"contact_uri_parameters",NULL)); + linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",LP_CONFIG_DEFAULT_INT(config,"reg_expires",600))); linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0)); diff --git a/include/sal/sal.h b/include/sal/sal.h index 655613661..f02656f2f 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -94,12 +94,7 @@ 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); @@ -107,6 +102,8 @@ 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); +void sal_address_set_params(SalAddress *addr, const char *params); +void sal_address_set_uri_params(SalAddress *addr, const char *params); Sal * sal_init(); void sal_uninit(Sal* sal); From 4212cc43b8e44d3fe3168ced0aea7d366e9d46ad Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 12 Dec 2013 11:23:01 +0100 Subject: [PATCH 045/439] add jni for contact parameters --- coreapi/linphonecore_jni.cc | 19 ++++++++++-- .../linphone/core/LinphoneProxyConfig.java | 30 +++++++++++++++++-- .../core/LinphoneProxyConfigImpl.java | 18 +++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 9840cc6b1..9773da678 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1397,10 +1397,25 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getProxy(JNIEn } } extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactParameters(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jparams) { - const char* params = env->GetStringUTFChars(jparams, NULL); + const char* params = jparams ? env->GetStringUTFChars(jparams, NULL) : NULL; linphone_proxy_config_set_contact_parameters((LinphoneProxyConfig*)proxyCfg, params); - env->ReleaseStringUTFChars(jparams, params); + if (jparams) env->ReleaseStringUTFChars(jparams, params); } +extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactUriParameters(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jparams) { + const char* params = jparams ? env->GetStringUTFChars(jparams, NULL) : NULL; + linphone_proxy_config_set_contact_uri_parameters((LinphoneProxyConfig*)proxyCfg, params); + if (jparams) env->ReleaseStringUTFChars(jparams, params); +} +extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getContactParameters(JNIEnv* env,jobject thiz,jlong proxyCfg) { + const char* params = linphone_proxy_config_get_contact_parameters((LinphoneProxyConfig*)proxyCfg); + return params ? env->NewStringUTF(params) : NULL; +} +extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getContactUriParameters(JNIEnv* env,jobject thiz,jlong proxyCfg) { + const char* params = linphone_proxy_config_get_contact_uri_parameters((LinphoneProxyConfig*)proxyCfg); + return params ? env->NewStringUTF(params) : NULL; +} + + extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_setRoute(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jroute) { if (jroute != NULL) { const char* route = env->GetStringUTFChars(jroute, NULL); diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index 8a5da47a8..90d91e73a 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -166,10 +166,34 @@ public interface LinphoneProxyConfig { /** - * Sets parameters for the contact - * @param parameters to add + * Set optional contact parameters that will be added to the contact information sent in the registration. + * @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else" + * + * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or android push id. + * As an example, the contact address in the SIP register sent will look like ;android-push-id=43143-DFE23F-2323-FA2232. + **/ + public void setContactParameters(String contact_params); + + /** + * Get the contact's parameters. + * @return */ - public void setContactParameters(String params); + public String getContactParameters(); + + /** + * Set optional contact parameters that will be added to the contact information sent in the registration, inside the URI. + * @param params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else" + * + * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id. + * As an example, the contact address in the SIP register sent will look like . + **/ + public void setContactUriParameters(String params); + + /** + * Get the contact's uri parameters. + * @return + */ + public String getContactUriParameters(); /** * Return the international prefix for the given country diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 2b304c8c1..9f24dcbe8 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -187,4 +187,22 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public int getPrivacy() { return getPrivacy(nativePtr); } + + private native String getContactParameters(long ptr); + @Override + public String getContactParameters() { + return getContactParameters(nativePtr); + } + + private native void setContactUriParameters(long ptr, String params); + @Override + public void setContactUriParameters(String params) { + setContactUriParameters(nativePtr,params); + } + + private native String getContactUriParameters(long ptr); + @Override + public String getContactUriParameters() { + return getContactUriParameters(nativePtr); + } } From 9149278c8dfa86f8de6230fe0dc854cf98be3c12 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 12 Dec 2013 17:25:25 +0100 Subject: [PATCH 046/439] relax tester delay to take into account a DNS packet loses --- coreapi/proxy.c | 9 +-------- tester/liblinphone_tester.c | 2 +- tester/register_tester.c | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index dbc39f58a..d5bbe3e47 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -320,11 +320,8 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy); char* proxy_string; -#ifndef USE_BELLESIP - char *contact; -#else LinphoneAddress *contact; -#endif + proxy_string=linphone_address_as_string_uri_only(proxy); linphone_address_destroy(proxy); if (obj->op) @@ -332,11 +329,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ 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,proxy_string,obj->reg_identity,obj->expires)==0) { diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 1df32f237..910cb43b3 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -137,7 +137,7 @@ bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int va 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); + return wait_for_until(lc_1, lc_2,counter,value,3000); } bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { int retry=0; diff --git a/tester/register_tester.c b/tester/register_tester.c index 9531c1447..6ee79f9cd 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -481,7 +481,7 @@ static void io_recv_error_late_recovery(){ 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)); + 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)+3000)); linphone_core_manager_destroy(mgr); } From 70f9617b508d3548b7d8caaa95ed7adfcea33aca Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 12 Dec 2013 17:25:15 +0100 Subject: [PATCH 047/439] minor changes --- coreapi/bellesip_sal/sal_op_presence.c | 2 -- coreapi/presence.c | 9 ++++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 2e6ea3fcd..9f7d6f871 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -44,8 +44,6 @@ void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceMo belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),content,content_length); ms_free(content); } - - } static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ diff --git a/coreapi/presence.c b/coreapi/presence.c index e4cd069b9..3d50548bb 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1896,7 +1896,7 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen if ((model == NULL) || (model->services == NULL)) { err = write_xml_presence_service(writer, NULL, contact); } else { - struct _presence_service_obj_st st; + struct _presence_service_obj_st st={0}; st.writer = writer; st.contact = contact; st.err = &err; @@ -1904,13 +1904,13 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen } } if ((err >= 0) && (model != NULL)) { - struct _presence_person_obj_st st; + struct _presence_person_obj_st st={0}; st.writer = writer; st.err = &err; ms_list_for_each2(model->persons, (MSIterate2Func)write_xml_presence_person_obj, &st); } if ((err >= 0) && (model != NULL)) { - struct _presence_note_obj_st st; + struct _presence_note_obj_st st={0}; st.writer = writer; st.ns = NULL; st.err = &err; @@ -1923,12 +1923,11 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen if (err >= 0) { err = xmlTextWriterEndDocument(writer); } - - xmlFreeTextWriter(writer); if (err > 0) { /* xmlTextWriterEndDocument returns the size of the content. */ *content = ms_strdup((char *)buf->content); } + xmlFreeTextWriter(writer); xmlBufferFree(buf); } From 95e3f26dcaa784972338833208cbfee0abf78841 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Dec 2013 10:22:28 +0100 Subject: [PATCH 048/439] implement manual mode refresher for generic subscribe --- coreapi/bellesip_sal/sal_op_events.c | 2 ++ coreapi/bellesip_sal/sal_op_impl.c | 6 ++++++ coreapi/callbacks.c | 2 ++ coreapi/event.c | 2 ++ coreapi/event.h | 5 +++-- coreapi/linphonecore.c | 2 ++ coreapi/linphonecore.h | 4 ++-- coreapi/misc.c | 5 +++++ include/sal/sal.h | 3 ++- tester/eventapi_tester.c | 30 ++++++++++++++++++++++------ tester/liblinphone_tester.h | 1 + 11 files changed, 51 insertions(+), 11 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 376a88bcd..1972c97f6 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -52,6 +52,8 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher if (status_code>=200){ sal_compute_sal_errors_from_code(status_code,&error,&sr); op->base.root->callbacks.subscribe_response(op,sss,error,sr); + }else if (status_code==0){ + op->base.root->callbacks.on_expire(op); } } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 49fa7c5f8..43e94227b 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -358,6 +358,9 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonNotAcceptable: ret=488; break; + case SalReasonNoMatch: + ret=481; + break; } return ret; } @@ -391,6 +394,9 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal *sal_err=SalErrorFailure; *sal_reason=SalReasonTemporarilyUnavailable; break; + case 481: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonNoMatch; case 486: *sal_err=SalErrorFailure; *sal_reason=SalReasonBusy; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index da674aac6..e1a32f56c 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1108,6 +1108,8 @@ static void on_expire(SalOp *op){ if (linphone_event_get_publish_state(lev)==LinphonePublishOk){ linphone_event_set_publish_state(lev,LinphonePublishExpiring); + }else if (linphone_event_get_subscription_state(lev)==LinphoneSubscriptionActive){ + linphone_event_set_state(lev,LinphoneSubscriptionExpiring); } } diff --git a/coreapi/event.c b/coreapi/event.c index 46de6b779..fe710e677 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -40,6 +40,7 @@ const char *linphone_subscription_state_to_string(LinphoneSubscriptionState stat case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive"; case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated"; case LinphoneSubscriptionError: return "LinphoneSubscriptionError"; + case LinphoneSubscriptionExpiring: return "LinphoneSubscriptionExpiring"; } return NULL; } @@ -124,6 +125,7 @@ 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); + sal_op_set_manual_refresher_mode(lev->op,lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1)); lev->resource_addr=linphone_address_clone(resource); lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op)); sal_subscribe(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); diff --git a/coreapi/event.h b/coreapi/event.h index 9acb94b2d..d3f869d68 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -57,7 +57,8 @@ enum _LinphoneSubscriptionState{ LinphoneSubscriptionPending, /**refresh_generic_subscribe property is set to 0.*/ }; /** @@ -72,7 +73,7 @@ LINPHONE_PUBLIC const char *linphone_subscription_state_to_string(LinphoneSubscr **/ enum _LinphonePublishState{ LinphonePublishNone, /**< Initial state, do not use**/ - LinphonePublishProgress, /**refresh_generic_publish property is set to 0.*/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5698d2272..511178c4c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5916,6 +5916,8 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "Unauthorized"; case LinphoneReasonNotAcceptable: return "Not acceptable here"; + case LinphoneReasonNoMatch: + return "No match"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 88e933e32..d083b07c8 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -165,8 +165,8 @@ enum _LinphoneReason{ LinphoneReasonIOError, /**number_of_LinphoneSubscriptionError++; mgr->lev=NULL; break; + case LinphoneSubscriptionExpiring: + counters->number_of_LinphoneSubscriptionExpiring++; + mgr->lev=NULL; + break; } } @@ -119,13 +123,18 @@ static void subscribe_test_declined(void) { linphone_core_manager_destroy(pauline); } +typedef enum RefreshTestType{ + NoRefresh, + AutoRefresh, + ManualRefresh +}RefreshTestType; -static void subscribe_test_with_args(bool_t terminated_by_subscriber, bool_t test_refreshing) { +static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTestType refresh_type) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneContent content={0}; LinphoneEvent *lev; - int expires= test_refreshing ? 4 : 600; + int expires= refresh_type!=NoRefresh ? 4 : 600; MSList* lcs=ms_list_append(NULL,marie->lc); @@ -147,9 +156,13 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, bool_t tes /*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){ + if (refresh_type==AutoRefresh){ wait_for_list(lcs,NULL,0,6000); CU_ASSERT_TRUE(linphone_event_get_subscription_state(pauline->lev)==LinphoneSubscriptionActive); + }else if (refresh_type==ManualRefresh){ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionExpiring,1,4000)); + linphone_event_update_subscribe(lev,NULL); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,2000)); } if (terminated_by_subscriber){ @@ -167,18 +180,22 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, bool_t tes } static void subscribe_test_terminated_by_subscriber(void){ - subscribe_test_with_args(TRUE,FALSE); + subscribe_test_with_args(TRUE,NoRefresh); } static void subscribe_test_terminated_by_notifier(void){ - subscribe_test_with_args(FALSE,FALSE); + subscribe_test_with_args(FALSE,NoRefresh); } /* Caution: this test does not really check that the subscribe are refreshed, because the core is not managing the expiration of * unrefreshed subscribe dialogs. So it is just checking that it is not crashing. */ static void subscribe_test_refreshed(void){ - subscribe_test_with_args(TRUE,TRUE); + subscribe_test_with_args(TRUE,AutoRefresh); +} + +static void subscribe_test_manually_refreshed(void){ + subscribe_test_with_args(TRUE,ManualRefresh); } static void publish_test_with_args(bool_t refresh){ @@ -234,6 +251,7 @@ test_t event_tests[] = { { "Subscribe declined" , subscribe_test_declined }, { "Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber }, { "Subscribe refreshed", subscribe_test_refreshed }, + { "Subscribe manually refreshed", subscribe_test_manually_refreshed }, { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier }, { "Publish", publish_test }, { "Publish without automatic refresh",publish_no_auto_test } diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index ae1fe453d..2a8e33af0 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -163,6 +163,7 @@ typedef struct _stats { int number_of_LinphoneSubscriptionActive; int number_of_LinphoneSubscriptionTerminated; int number_of_LinphoneSubscriptionError; + int number_of_LinphoneSubscriptionExpiring; int number_of_LinphonePublishProgress; int number_of_LinphonePublishOk; From f02255ad6aee17cbbebcf258bb925306e2b436ca Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Dec 2013 11:31:25 +0100 Subject: [PATCH 049/439] add new SubscriptionState.Expiring --- java/common/org/linphone/core/PublishState.java | 1 + java/common/org/linphone/core/SubscriptionState.java | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/java/common/org/linphone/core/PublishState.java b/java/common/org/linphone/core/PublishState.java index 7dfe86e3e..b89c831eb 100644 --- a/java/common/org/linphone/core/PublishState.java +++ b/java/common/org/linphone/core/PublishState.java @@ -19,6 +19,7 @@ public enum PublishState { Error(3), /** * Publish is about to expire. Application can trigger a refresh by calling {@link LinphoneCore.updatePublish()} + * [sip]->refresh_generic_subscribe property is set to 0. */ Expiring(4), /** diff --git a/java/common/org/linphone/core/SubscriptionState.java b/java/common/org/linphone/core/SubscriptionState.java index a6e84ec6a..987090409 100644 --- a/java/common/org/linphone/core/SubscriptionState.java +++ b/java/common/org/linphone/core/SubscriptionState.java @@ -28,8 +28,12 @@ public enum SubscriptionState { /** * Subscription encountered an error, indicated by { @link LinphoneEvent.getReason() } */ - Error(6); + Error(6), + /** + * Subscription is about to expire, only notified if [sip]->refresh_generic_subscribe property is set to 0 + */ + Expiring(7); protected final int mValue; private SubscriptionState(int value){ mValue=value; @@ -43,6 +47,7 @@ public enum SubscriptionState { case 4: return Active; case 5: return Terminated; case 6: return Error; + case 7: return Expiring; default: throw new LinphoneCoreException("Unhandled enum value "+value+" for SubscriptionState"); } From fc7f4002ac787c2fa16b94837f0ef782927f8737 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Dec 2013 11:47:23 +0100 Subject: [PATCH 050/439] add missing enum members --- java/common/org/linphone/core/Reason.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/java/common/org/linphone/core/Reason.java b/java/common/org/linphone/core/Reason.java index 8c954ab58..e70c9dc09 100644 --- a/java/common/org/linphone/core/Reason.java +++ b/java/common/org/linphone/core/Reason.java @@ -48,7 +48,15 @@ public class Reason { * Operation not authorized because no credentials found * */ static public Reason Unauthorized = new Reason(10,"Unauthorized"); - + /** + * Operation was rejected by remote, for example a LinphoneCore.updateCall() + */ + static public Reason NotAcceptable = new Reason(11,"NotAcceptable"); + /** + * Operation was rejected by remote due to request unmatched to any context. + */ + static public Reason NoMatch = new Reason(12,"NoMatch"); + protected final int mValue; private final String mStringValue; From e79a8c4ee50d6e413347c4f7afd0c62acd1b1e87 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Dec 2013 14:39:08 +0100 Subject: [PATCH 051/439] fix refresh property behaviour --- coreapi/event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/event.c b/coreapi/event.c index fe710e677..5ddec23fd 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -125,7 +125,7 @@ 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); - sal_op_set_manual_refresher_mode(lev->op,lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1)); + sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1)); lev->resource_addr=linphone_address_clone(resource); lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op)); sal_subscribe(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); @@ -189,7 +189,7 @@ LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *re 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_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); err=sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); if (err==0){ linphone_event_set_publish_state(lev,LinphonePublishProgress); From ded4d06469fe4d5498ad756768926c3b31b370d5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Dec 2013 17:33:46 +0100 Subject: [PATCH 052/439] add linphone_core_start_refered_call() to allow application to control how to execute an incoming call transfer belle-sip upgrade required. --- coreapi/callbacks.c | 13 +++--------- coreapi/linphonecore.c | 46 ++++++++++++++++++++++++++++------------ coreapi/linphonecore.h | 2 ++ coreapi/private.h | 2 +- tester/eventapi_tester.c | 6 ++++-- 5 files changed, 42 insertions(+), 27 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e1a32f56c..e73a60fa9 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -363,7 +363,7 @@ static void call_accepted(SalOp *op){ linphone_core_update_streams (lc,call,md); linphone_call_set_state(call,LinphoneCallPaused,"Call paused"); if (call->refer_pending) - linphone_core_start_refered_call(lc,call); + linphone_core_start_refered_call(lc,call,NULL); }else if (sal_media_description_has_dir(md,SalStreamRecvOnly)){ /*we are put on hold when the call is initially accepted */ if (lc->vtable.display_status){ @@ -536,7 +536,7 @@ static void call_terminated(SalOp *op, const char *from){ } ms_message("Current call terminated..."); if (call->refer_pending){ - linphone_core_start_refered_call(lc,call); + linphone_core_start_refered_call(lc,call,NULL); } //we stop the call only if we have this current call or if we are in call if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) { @@ -808,14 +808,7 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ lc->vtable.display_status(lc,msg); ms_free(msg); } - if (call->state!=LinphoneCallPaused){ - ms_message("Automatically pausing current call to accept transfer."); - _linphone_core_pause_call(lc,call); - call->was_automatically_paused=TRUE; - /*then we will start the refered when the pause is accepted, in order to serialize transactions within the dialog. - * Indeed we need to avoid to send a NOTIFY to inform about of state of the refered call while the pause isn't completed. - **/ - }else linphone_core_start_refered_call(lc,call); + if (call->refer_pending) linphone_core_start_refered_call(lc,call,NULL); }else if (lc->vtable.refer_received){ lc->vtable.refer_received(lc,referto); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 511178c4c..c9cd717a2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2364,21 +2364,39 @@ const char * linphone_core_get_route(LinphoneCore *lc){ return route; } -void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){ - if (call->refer_pending){ - LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc); - LinphoneCall *newcall; - cp->has_video = call->current_params.has_video; /*start the call to refer-target with video enabled if original call had video*/ - cp->referer=call; - ms_message("Starting new call to refered address %s",call->refer_to); - call->refer_pending=FALSE; - newcall=linphone_core_invite_with_params(lc,call->refer_to,cp); - linphone_call_params_destroy(cp); - if (newcall) { - call->transfer_target=linphone_call_ref(newcall); - linphone_core_notify_refer_state(lc,call,newcall); - } +/** + * Start a new call as a consequence of a transfer request received from a call. + * This function is for advanced usage: the execution of transfers is automatically managed by the LinphoneCore. However if an application + * wants to have control over the call parameters for the new call, it should call this function immediately during the LinphoneCallRefered notification. + * @see LinphoneCoreVTable::call_state_changed + * @param lc the LinphoneCore + * @param call a call that has just been notified about LinphoneCallRefered state event. + * @param params the call parameters to be applied to the new call. + * @return a LinphoneCall corresponding to the new call that is attempted to the transfer destination. +**/ +LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ + LinphoneCallParams *cp=params ? linphone_call_params_copy(params) : linphone_core_create_default_call_parameters(lc); + LinphoneCall *newcall; + + if (call->state!=LinphoneCallPaused){ + ms_message("Automatically pausing current call to accept transfer."); + _linphone_core_pause_call(lc,call); + call->was_automatically_paused=TRUE; } + + if (!params){ + cp->has_video = call->current_params.has_video; /*start the call to refer-target with video enabled if original call had video*/ + } + cp->referer=call; + ms_message("Starting new call to refered address %s",call->refer_to); + call->refer_pending=FALSE; + newcall=linphone_core_invite_with_params(lc,call->refer_to,cp); + linphone_call_params_destroy(cp); + if (newcall) { + call->transfer_target=linphone_call_ref(newcall); + linphone_core_notify_refer_state(lc,call,newcall); + } + return newcall; } void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d083b07c8..ae7998db6 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1286,6 +1286,8 @@ LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall * LINPHONE_PUBLIC int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest); +LINPHONE_PUBLIC LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); + LINPHONE_PUBLIC bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); LINPHONE_PUBLIC bool_t linphone_core_in_call(const LinphoneCore *lc); diff --git a/coreapi/private.h b/coreapi/private.h index b5799632a..76181edc2 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -367,7 +367,7 @@ 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); +void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); extern SalCallbacks linphone_sal_callbacks; diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index acd1d3010..9dfaf2af7 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -137,9 +137,11 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes int expires= refresh_type!=NoRefresh ? 4 : 600; MSList* lcs=ms_list_append(NULL,marie->lc); - lcs=ms_list_append(lcs,pauline->lc); + if (refresh_type==ManualRefresh){ + lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0); + } content.type="application"; content.subtype="somexml"; @@ -212,7 +214,7 @@ static void publish_test_with_args(bool_t refresh){ content.data=(char*)subscribe_content; content.size=strlen(subscribe_content); - lp_config_set_int(marie->lc->config,"sip","refresh_generic_publish",!refresh); + 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); From fda6a31d1f84c1308fe6f6aa106b567036879c3b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Dec 2013 17:56:03 +0100 Subject: [PATCH 053/439] add jni for LinphoneCore.startReferedCall() --- coreapi/linphonecore_jni.cc | 5 +++++ coreapi/private.h | 1 - java/common/org/linphone/core/LinphoneCore.java | 10 ++++++++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 7 +++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 9773da678..4dc3b6d04 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2882,6 +2882,11 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_transferCallToAnother(JN return (jint)linphone_core_transfer_call_to_another((LinphoneCore *) pCore, (LinphoneCall *) pCall, (LinphoneCall *) pDestCall); } +extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_startReferedCall(JNIEnv *env, jobject thiz, jlong lc, jlong callptr, jlong params){ + LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc); + return lcd->getCall(env,linphone_core_start_refered_call((LinphoneCore *)lc, (LinphoneCall *)callptr, (const LinphoneCallParams *)params)); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setZrtpSecretsCache(JNIEnv *env,jobject thiz,jlong pCore, jstring jFile) { if (jFile) { const char* cFile=env->GetStringUTFChars(jFile, NULL); diff --git a/coreapi/private.h b/coreapi/private.h index 76181edc2..3f198579c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -367,7 +367,6 @@ 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, const LinphoneCallParams *params); void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); extern SalCallbacks linphone_sal_callbacks; diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index ef310bc9a..0cedc40f8 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1088,6 +1088,16 @@ public interface LinphoneCore { * @param dest a running call whose remote person will receive the transfer **/ void transferCallToAnother(LinphoneCall callToTransfer, LinphoneCall destination); + + /** + * Start a new call as a consequence of a transfer request received from a call. + * This function is for advanced usage: the execution of transfers is automatically managed by the LinphoneCore. However if an application + * wants to have control over the call parameters for the new call, it should call this function immediately during the LinphoneCallRefered notification. + * @param call a call that has just been notified about LinphoneCallRefered state event. + * @param params the call parameters to be applied to the new call. + * @return a LinphoneCall corresponding to the new call that is attempted to the transfer destination. + **/ + LinphoneCall startReferedCall(LinphoneCall call, LinphoneCallParams params); /** * Search from the list of current calls if a remote address match uri * @param uri which should match call remote uri diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 420547e57..f9a61acf8 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -1081,4 +1081,11 @@ class LinphoneCoreImpl implements LinphoneCore { return new LinphoneAuthInfoImpl(ptr); } + private native LinphoneCall startReferedCall(long corePtr, long callptr, long paramsPtr); + @Override + public LinphoneCall startReferedCall(LinphoneCall call, + LinphoneCallParams params) { + long ptrParams =((LinphoneCallParamsImpl)params).nativePtr; + return startReferedCall(nativePtr, getCallPtr(call), ptrParams); + } } From ffaf96828f3d457b99bc9bf527997859412b3693 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 17 Dec 2013 11:56:00 +0100 Subject: [PATCH 054/439] Implement fully compatible IPv4/IPv6 mode. Requires belle-sip upgrade. --- coreapi/bellesip_sal/sal_address_impl.c | 11 ++++++++ coreapi/bellesip_sal/sal_op_impl.c | 26 ++++++++++++++++++ coreapi/linphonecall.c | 36 +++++++++++++++++++++---- coreapi/linphonecore.c | 26 +++++++++++++----- coreapi/misc.c | 17 +++++++----- coreapi/private.h | 3 ++- include/sal/sal.h | 2 ++ oRTP | 2 +- 8 files changed, 104 insertions(+), 19 deletions(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 26e29b321..01a5b6229 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -179,6 +179,17 @@ void sal_address_unref(SalAddress *addr){ belle_sip_object_unref(BELLE_SIP_HEADER_ADDRESS(addr)); } +bool_t sal_address_is_ipv6(SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + if (uri){ + const char *host=belle_sip_uri_get_host(uri); + if (host && strchr(host,':')!=NULL) + return TRUE; + } + return FALSE; +} + void sal_address_destroy(SalAddress *addr){ sal_address_unref(addr); } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 43e94227b..47958ac6e 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -612,3 +612,29 @@ bool_t sal_op_is_secure(const SalOp* op) { void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled){ op->manual_refresher=enabled; } + +bool_t sal_op_is_ipv6(SalOp *op){ + belle_sip_transaction_t *tr=NULL; + belle_sip_header_address_t *contact; + belle_sip_request_t *req; + + if (op->refresher) + tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(op->refresher); + + if (tr==NULL) + tr=(belle_sip_transaction_t *)op->pending_client_trans; + if (tr==NULL) + tr=(belle_sip_transaction_t *)op->pending_server_trans; + + if (tr==NULL){ + ms_error("Unable to determine IP version from signaling operation."); + return FALSE; + } + req=belle_sip_transaction_get_request(tr); + contact=(belle_sip_header_address_t*)belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); + if (!contact){ + ms_error("Unable to determine IP version from signaling operation, no contact header found."); + } + return sal_address_is_ipv6((SalAddress*)contact); +} + diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 908157e48..19caa2059 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -501,12 +501,32 @@ void linphone_call_create_op(LinphoneCall *call){ /*else privacy might be set by proxy */ } +/* + * Choose IP version we are going to use for RTP socket. + * The algorithm is as follows: + * - if ipv6 is disabled at the core level, it is always AF_INET + * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6. + * - Otherwise, if the call is done through a known proxy config, then use the information obtained during REGISTER + * to know if IPv6 is supported by the server. +**/ +static void linphone_call_outgoing_select_ip_version(LinphoneCall *call, LinphoneAddress *to, LinphoneProxyConfig *cfg){ + if (linphone_core_ipv6_enabled(call->core)){ + call->af=AF_INET; + if (sal_address_is_ipv6((SalAddress*)to)){ + call->af=AF_INET6; + }else if (cfg && cfg->op){ + call->af=sal_op_is_ipv6(cfg->op) ? AF_INET6 : AF_INET; + } + }else call->af=AF_INET; +} + 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_outgoing_select_ip_version(call,to,cfg); + linphone_core_get_local_ip(lc,call->af,call->localip); linphone_call_init_common(call,from,to); _linphone_call_params_copy(&call->params,params); @@ -535,6 +555,12 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr return call; } +static void linphone_call_incoming_select_ip_version(LinphoneCall *call){ + if (linphone_core_ipv6_enabled(call->core)){ + call->af=sal_op_is_ipv6(call->op) ? AF_INET6 : AF_INET; + }else call->af=AF_INET; +} + LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call=ms_new0(LinphoneCall,1); char *from_str; @@ -544,7 +570,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro sal_op_set_user_pointer(op,call); call->op=op; call->core=lc; - + linphone_call_incoming_select_ip_version(call); if (lc->sip_conf.ping_with_options){ #ifdef BUILD_UPNP @@ -565,7 +591,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro } linphone_address_clean(from); - linphone_core_get_local_ip(lc,NULL,call->localip); + linphone_core_get_local_ip(lc,call->af,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); @@ -1331,7 +1357,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ int dscp; if (call->audiostream != NULL) return; - call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc)); + call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,call->af==AF_INET6); dscp=linphone_core_get_audio_dscp(lc); if (dscp!=-1) audio_stream_set_dscp(audiostream,dscp); @@ -1395,7 +1421,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ 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)); + call->videostream=video_stream_new(call->video_port,call->video_port+1,call->af==AF_INET6); if (dscp!=-1) video_stream_set_dscp(call->videostream,dscp); video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c9cd717a2..bc256c466 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1443,8 +1443,9 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) } +/*Returns the local ip that routes to the internet, or guessed by other special means (upnp)*/ /*result must be an array of chars at least LINPHONE_IPADDR_SIZE */ -void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){ +void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result){ const char *ip; if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress && (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){ @@ -1459,10 +1460,23 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result return; } #endif //BUILD_UPNP - if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0) + if (af==AF_UNSPEC){ + if (linphone_core_ipv6_enabled(lc)){ + bool_t has_ipv6; + has_ipv6=linphone_core_get_local_ip_for(AF_INET6,NULL,result)==0; + if (strcmp(result,"::1")!=0) + return; /*this machine has real ipv6 connectivity*/ + if (linphone_core_get_local_ip_for(AF_INET,NULL,result)==0 && strcmp(result,"::1")!=0) + return; /*this machine has only ipv4 connectivity*/ + if (has_ipv6){ + /*this machine has only local loopback for both ipv4 and ipv6, so prefer ipv6*/ + strncpy(result,"::1",LINPHONE_IPADDR_SIZE); + return; + } + }else af=AF_INET; + } + if (linphone_core_get_local_ip_for(af,NULL,result)==0) return; - /*else fallback to SAL routine that will attempt to find the most realistic interface */ - sal_get_default_local_ip(lc->sal,lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE); } static void update_primary_contact(LinphoneCore *lc){ @@ -1479,7 +1493,7 @@ static void update_primary_contact(LinphoneCore *lc){ ms_error("Could not parse identity contact !"); url=linphone_address_new("sip:unknown@unkwownhost"); } - linphone_core_get_local_ip(lc, NULL, tmp); + linphone_core_get_local_ip(lc, AF_UNSPEC, tmp); if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){ ms_warning("Local loopback network only !"); lc->sip_conf.loopback_only=TRUE; @@ -2027,7 +2041,7 @@ static void monitor_network_state(LinphoneCore *lc, time_t curtime){ /* only do the network up checking every five seconds */ if (lc->network_last_check==0 || (curtime-lc->network_last_check)>=5){ - linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,result); + linphone_core_get_local_ip(lc,AF_UNSPEC,result); if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){ new_status=TRUE; }else new_status=FALSE; diff --git a/coreapi/misc.c b/coreapi/misc.c index c64ace809..aaf8c2167 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -637,12 +637,16 @@ static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addr } void linphone_core_resolve_stun_server(LinphoneCore *lc){ + /* + * WARNING: stun server resolution only done in IPv4. + * TODO: use IPv6 resolution if linphone_core_ipv6_enabled()==TRUE and use V4Mapped addresses for ICE gathering. + */ const char *server=lc->net_conf.stun_server; if (lc->sal && server){ char host[NI_MAXHOST]; int port=3478; linphone_parse_host_port(server,host,sizeof(host),&port); - lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_UNSPEC,(SalResolverCallback)stun_server_resolved,lc); + lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_INET,(SalResolverCallback)stun_server_resolved,lc); } } @@ -685,8 +689,8 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) video_check_list = ice_session_check_list(call->ice_session, 1); if (audio_check_list == NULL) return -1; - if (lc->sip_conf.ipv6_enabled){ - ms_warning("stun support is not implemented for ipv6"); + if (call->af==AF_INET6){ + ms_warning("Ice gathering is not implemented for ipv6"); return -1; } ai=linphone_core_get_stun_server_addrinfo(lc); @@ -1133,12 +1137,12 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul socklen_t s; memset(&hints,0,sizeof(hints)); - hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET; + hints.ai_family=type; hints.ai_socktype=SOCK_DGRAM; /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/ err=getaddrinfo(dest,"5060",&hints,&res); if (err!=0){ - ms_error("getaddrinfo() error: %s",gai_strerror(err)); + ms_error("getaddrinfo() error for %s : %s",dest, gai_strerror(err)); return -1; } if (res==NULL){ @@ -1153,7 +1157,8 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul } err=connect(sock,res->ai_addr,res->ai_addrlen); if (err<0) { - ms_error("Error in connect: %s",strerror(errno)); + /*the network isn't reachable*/ + if (getSocketErrorCode()!=ENETUNREACH) ms_error("Error in connect: %s",strerror(errno)); freeaddrinfo(res); close_socket(sock); return -1; diff --git a/coreapi/private.h b/coreapi/private.h index 3f198579c..69ee5b61e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -154,6 +154,7 @@ struct _LinphoneCall { int magic; /*used to distinguish from proxy config*/ struct _LinphoneCore *core; + int af; /*the address family to prefer for RTP path, guessed from signaling path*/ SalMediaDescription *localdesc; SalMediaDescription *resultdesc; LinphoneCallDir dir; @@ -263,7 +264,7 @@ int set_lock_file(); int get_lock_file(); int remove_lock_file(); void check_sound_device(LinphoneCore *lc); -void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result); +void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result); bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); diff --git a/include/sal/sal.h b/include/sal/sal.h index 2d7f8994d..b76d70b05 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -104,6 +104,7 @@ void sal_address_set_transport(SalAddress* addr,SalTransport transport); void sal_address_set_transport_name(SalAddress* addr,const char* transport); void sal_address_set_params(SalAddress *addr, const char *params); void sal_address_set_uri_params(SalAddress *addr, const char *params); +bool_t sal_address_is_ipv6(SalAddress *addr); Sal * sal_init(); void sal_uninit(Sal* sal); @@ -556,6 +557,7 @@ 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); +bool_t sal_op_is_ipv6(SalOp *op); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); diff --git a/oRTP b/oRTP index fcc51caa1..123ef1a55 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit fcc51caa15def815189a388e878877a5354850e6 +Subproject commit 123ef1a55c321826966a3a375bee09b558ae170d From b560f773f6092175b648d72ead0e16fe9c798dae Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 18 Dec 2013 11:50:54 +0100 Subject: [PATCH 055/439] Added preliminary work on complex LDAP authentication (not yet working). Basic auth still works. + cleaned up some traces --- coreapi/ldap/ldapprovider.c | 142 +++++++++++++++++++++++++++--------- gtk/main.c | 3 +- 2 files changed, 109 insertions(+), 36 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 1e2b942b6..35a7638a0 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -21,6 +21,7 @@ #include #include +#include #define MAX_RUNNING_REQUESTS 10 @@ -47,7 +48,8 @@ struct _LinphoneLDAPContactProvider uint req_count; // bind transaction - uint bind_msgid; + int bind_msgid; + const char* auth_mechanism; bool_t connected; // config @@ -86,7 +88,6 @@ struct _LinphoneLDAPContactSearch * *************************/ LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* cp, const char* predicate, ContactSearchCallback cb, void* cb_data) - { LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search); @@ -113,6 +114,7 @@ LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPConta &timeout, // server timeout for the search cp->max_results,// max result number &search->msgid ); + if( ret != LDAP_SUCCESS ){ ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret)); belle_sip_object_unref(search); @@ -159,6 +161,8 @@ static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_ static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req); static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); static bool_t linphone_ldap_contact_provider_iterate(void *data); +static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, unsigned flags, void *defaults, void *sasl_interact); + /* Authentication methods */ struct AuthMethodDescription{ @@ -207,13 +211,34 @@ static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* static int linphone_ldap_contact_provider_parse_bind_results( LinphoneLDAPContactProvider* obj, LDAPMessage* results ) { - int ret = ldap_parse_sasl_bind_result(obj->ld, results, NULL, 0); - if( ret != LDAP_SUCCESS ){ - ms_error("ldap_parse_sasl_bind_result failed"); + int ret; + if( obj->auth_method == ANONYMOUS ) { + ms_message("ANONYMOUS BIND OK"); + ret = LDAP_SUCCESS; } else { - obj->connected = TRUE; + ms_message("COMPLICATED BIND follow-up"); + ret = ldap_sasl_interactive_bind(obj->ld, + NULL, // dn, should be NULL + "DIGEST-MD5", + NULL,NULL, // server and client controls + LDAP_SASL_QUIET, // never prompt, only use callback + linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed + obj, // private data + results, // result, to pass later on when a ldap_result() comes + &obj->auth_mechanism, + &obj->bind_msgid ); + if( ret != LDAP_SUCCESS){ + ms_error("ldap_parse_sasl_bind_result failed(%d)", ret); + } } + + if( ret == LDAP_SUCCESS ){ + obj->connected = TRUE; + obj->bind_msgid = 0; + } + return ret; + } static int linphone_ldap_contact_provider_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value) @@ -264,7 +289,7 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon while( values && *it && (*it)->bv_val && (*it)->bv_len ) { - ms_message("%s -> %s", attr, (*it)->bv_val); + //ms_message("%s -> %s", attr, (*it)->bv_val); contact_complete = linphone_ldap_contact_provider_complete_contact(obj, &ldap_data, attr, (*it)->bv_val); if( contact_complete ) break; @@ -288,7 +313,7 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon linphone_friend_set_name(lf, ldap_data.name); req->found_entries = ms_list_append(req->found_entries, lf); req->found_count++; - ms_message("Added friend %s / %s", ldap_data.name, ldap_data.sip); + //ms_message("Added friend %s / %s", ldap_data.name, ldap_data.sip); ms_free(ldap_data.sip); ms_free(ldap_data.name); linphone_address_destroy(la); @@ -311,7 +336,7 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon break; - default: ms_message("Unhandled message type %x", msgtype); break; + default: ms_message("[LDAP] Unhandled message type %x", msgtype); break; } } @@ -343,7 +368,6 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) ms_error("Bad msgid"); } else { linphone_ldap_contact_provider_parse_bind_results( obj, results ); - obj->bind_msgid = 0; // we're bound now, don't bother checking again } break; } @@ -457,8 +481,7 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide /* * Get authentication method */ - obj->auth_method = - linphone_ldap_contact_provider_auth_method( + obj->auth_method = linphone_ldap_contact_provider_auth_method( linphone_dictionary_get_string(obj->config, "auth_method", "anonymous") ); @@ -490,33 +513,79 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide ms_free(attributes_list); } +static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, + unsigned flags, + void *defaults, + void *sasl_interact) +{ + sasl_interact_t *interact = (sasl_interact_t*)sasl_interact; + LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(defaults); + ms_message("bind_interact called: ld %p, flags %x, default %p, interact %p", + ld, flags, defaults, sasl_interact); + + if( ld == NULL ) return LDAP_PARAM_ERROR; + + while( interact->id != SASL_CB_LIST_END ) { + + const char *dflt = interact->defresult; + + switch( interact->id ) { + case SASL_CB_GETREALM: + ms_message("* SASL_CB_GETREALM"); + dflt=NULL; + break; + case SASL_CB_USER: + case SASL_CB_AUTHNAME: + ms_message("* SASL_CB_AUTHNAME -> %s", obj->username); + dflt=obj->username; + break; + case SASL_CB_PASS: + ms_message("* SASL_CB_PASS -> %s", obj->password); + dflt=obj->password; + break; + default: + ms_message("my_sasl_interact asked for unknown %lx\n",interact->id); + } + interact->result = (dflt && *dflt) ? dflt : (const char*)""; + interact->len = strlen( (const char*)interact->result ); + + interact++; + } + return LDAP_SUCCESS; +} + static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) { - struct berval password = { strlen( obj->password ), ms_strdup(obj->password) }; int ret; - int bind_msgid = 0; + const char* auth_mechanism = linphone_dictionary_get_string(obj->config, "auth_method", "anonymous"); + LDAPAuthMethod method = obj->auth_method; - switch( obj->auth_method ){ - case ANONYMOUS: - default: - { - char *auth = NULL; - ret = ldap_sasl_bind( obj->ld, obj->base_object, auth, &password, NULL, NULL, &bind_msgid); - if( ret == LDAP_SUCCESS ) { - obj->bind_msgid = bind_msgid; - } else { - int err; - ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err); - ms_error("ldap_sasl_bind error %d (%s)", err, ldap_err2string(err) ); - } - break; + if( method == ANONYMOUS ){ + // for anonymous authentication, use a simple sasl_bind + struct berval creds = {strlen(obj->password), ms_strdup(obj->password)}; + ret = ldap_sasl_bind(obj->ld, obj->base_object, NULL, &creds, NULL, NULL, &obj->bind_msgid); + if(creds.bv_val) ms_free(creds.bv_val); + } else { + ret = ldap_sasl_interactive_bind(obj->ld, + NULL, // dn, should be NULL + "SIMPLE",//"DIGEST-MD5", + NULL,NULL, // server and client controls + LDAP_SASL_QUIET, // never prompt, only use callback + linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed + obj, // private data + NULL, // result, to pass later on when a ldap_result() comes + &obj->auth_mechanism, + &obj->bind_msgid ); } - case SASL: - { - break; + if( ret == LDAP_SUCCESS || ret == LDAP_SASL_BIND_IN_PROGRESS ) { + if( ret == LDAP_SASL_BIND_IN_PROGRESS) ms_message("BIND_IN_PROGRESS"); + ms_message("LDAP bind request sent, auth: %s, msgid %x", obj->auth_mechanism?obj->auth_mechanism:"-", obj->bind_msgid); + } else { + int err; + ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err); + ms_error("ldap_sasl_bind error returned %d, err %d (%s), auth_method: %s", + ret, err, ldap_err2string(err), auth_mechanism ); } - } - if(password.bv_val) ms_free(password.bv_val); return 0; } @@ -526,6 +595,11 @@ unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPCon return obj->max_results; } +static void linphone_ldap_contact_provider_config_dump_cb(const char*key, void* value, void* userdata) +{ + ms_message("- %s -> %s", key, (const char* )value); +} + LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config) { LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider); @@ -540,6 +614,7 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* belle_sip_object_unref(obj); obj = NULL; } else { + linphone_dictionary_foreach( config, linphone_ldap_contact_provider_config_dump_cb, 0 ); linphone_ldap_contact_provider_loadconfig(obj, config); int ret = ldap_initialize(&(obj->ld),obj->server); @@ -619,7 +694,6 @@ static LinphoneLDAPContactSearch* linphone_ldap_contact_provider_begin_search ( // if we're not yet connected, bind if( !obj->connected ) linphone_ldap_contact_provider_bind(obj); - LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create ( obj, predicate, cb, cb_data ); if ( request != NULL ) { diff --git a/gtk/main.c b/gtk/main.c index d9b86a4b4..db9568cb0 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -661,7 +661,6 @@ static gboolean uribar_completion_matchfunc(GtkEntryCompletion *completion, cons gboolean ret = FALSE; gchar *tmp= NULL; gtk_tree_model_get(gtk_entry_completion_get_model(completion),iter,0,&address,-1); - ms_message("In matchFunc(): key=%s, addr=%s",key,address); tmp = g_utf8_casefold(address,-1); if (tmp){ @@ -761,7 +760,7 @@ void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* fri GtkListStore* list = GTK_LIST_STORE(model); gboolean valid; - // clear completion list from previous non-history completion suggestions + // clear completion list from previous non-history entries valid = gtk_tree_model_get_iter_first(model,&iter); while(valid) { From 57640825a4796f21dfd0cabb7745e946c633bfda Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 18 Dec 2013 15:22:01 +0100 Subject: [PATCH 056/439] Remove unneeded messages in LDAP --- coreapi/contactprovider.c | 3 --- coreapi/ldap/ldapprovider.c | 21 ++++----------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index 96a941b1f..835e8c62a 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -30,12 +30,9 @@ void linphone_contact_search_init(LinphoneContactSearch* obj, obj->predicate = ms_strdup(predicate?predicate:""); obj->cb = cb; obj->data = cb_data; - ms_message("LinphoneContactSearch@%p(id:%d, pred:%s, cb:%p, data:%p)", - obj, obj->id, obj->predicate, obj->cb, obj->data); } static void linphone_contact_search_destroy( LinphoneContactSearch* req) { - ms_message( "~LinphoneContactSearch(%p)", req); if( req->predicate ) ms_free(req->predicate); } diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 35a7638a0..2c783d6fa 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -138,7 +138,7 @@ unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj ) { - ms_message("~LinphoneLDAPContactSearch(%p)", obj); + //ms_message("~LinphoneLDAPContactSearch(%p)", obj); ms_list_for_each(obj->found_entries, linphone_ldap_contact_search_destroy_friend); obj->found_entries = ms_list_free(obj->found_entries); if( obj->filter ) ms_free(obj->filter); @@ -195,7 +195,7 @@ static void linphone_ldap_contact_provider_destroy_request_cb(void *req) static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj ) { - ms_message("linphone_ldap_contact_provider_destroy"); + //ms_message("linphone_ldap_contact_provider_destroy"); linphone_core_remove_iterate_hook(LINPHONE_CONTACT_PROVIDER(obj)->lc, linphone_ldap_contact_provider_iterate,obj); // clean pending requests @@ -216,10 +216,10 @@ static int linphone_ldap_contact_provider_parse_bind_results( LinphoneLDAPContac ms_message("ANONYMOUS BIND OK"); ret = LDAP_SUCCESS; } else { - ms_message("COMPLICATED BIND follow-up"); + ms_message("Advanced BIND follow-up"); ret = ldap_sasl_interactive_bind(obj->ld, NULL, // dn, should be NULL - "DIGEST-MD5", + "DIGEST-MD5", // TODO: use defined auth NULL,NULL, // server and client controls LDAP_SASL_QUIET, // never prompt, only use callback linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed @@ -275,13 +275,6 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon bool_t contact_complete = FALSE; BerElement* ber = NULL; char* attr = ldap_first_attribute(obj->ld, entry, &ber); - char* dn = ldap_get_dn(obj->ld, entry); - - - if( dn ){ - //ms_message("search result: dn: %s", dn); - ldap_memfree(dn); - } while( attr ){ struct berval** values = ldap_get_values_len(obj->ld, entry, attr); @@ -289,8 +282,6 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon while( values && *it && (*it)->bv_val && (*it)->bv_len ) { - //ms_message("%s -> %s", attr, (*it)->bv_val); - contact_complete = linphone_ldap_contact_provider_complete_contact(obj, &ldap_data, attr, (*it)->bv_val); if( contact_complete ) break; @@ -351,8 +342,6 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) int ret = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ONE, &timeout, &results); - if( ret != 0 && ret != -1) ms_message("ldap_result %x", ret); - switch( ret ){ case -1: { @@ -380,7 +369,6 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) LDAPMessage* message = ldap_first_message(obj->ld, results); LinphoneLDAPContactSearch* req = linphone_ldap_contact_provider_request_search(obj, ldap_msgid(message)); while( message != NULL ){ - //ms_message("Message @%p:id %d / type %x / associated request: %p", message, ldap_msgid(message), ldap_msgtype(message), req); linphone_ldap_contact_provider_handle_search_result(obj, req, message ); message = ldap_next_message(obj->ld, message); } @@ -629,7 +617,6 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* obj = NULL; } else { // register our hook into iterate so that LDAP can do its magic asynchronously. - //linphone_ldap_contact_provider_bind(obj); linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); } } From 51302b1144d440213a6cf89858fdd1706b578229 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 18 Dec 2013 15:32:25 +0100 Subject: [PATCH 057/439] fix crash when calling an empty uri fix property box udp port adjustement , that shall start to 0 --- coreapi/linphonecore.c | 2 ++ gtk/parameters.ui | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6741073b1..870512454 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2297,6 +2297,8 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) LinphoneProxyConfig *proxy=lc->default_proxy; char *tmpurl; LinphoneAddress *uri; + + if (*url=='\0') return NULL; if (is_enum(url,&enum_domain)){ if (lc->vtable.display_status!=NULL) diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 21464d9e4..5f42cf9c5 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -48,7 +48,6 @@ 10 - 1 65535 5060 1 From 0bbefc1e7b2fa311e983259f934eb2c9102e92f4 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 18 Dec 2013 16:07:25 +0100 Subject: [PATCH 058/439] Fix compilation and runtime when no LDAP is asked. --- configure.ac | 19 ++++++++++++++----- gtk/linphone.h | 8 ++++++-- gtk/main.c | 14 ++++++++------ gtk/propertybox.c | 3 +++ 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 19087a244..a35089e36 100644 --- a/configure.ac +++ b/configure.ac @@ -167,21 +167,30 @@ AC_ARG_ENABLE(x11, dnl conditional build of LDAP support AC_ARG_ENABLE(ldap, - [AS_HELP_STRING([--disable-ldap], [Disable LDAP support (default=no)])], + [AS_HELP_STRING([--enable-ldap], [Enables LDAP support (default=no)])], [case "${enableval}" in yes) enable_ldap=true ;; no) enable_ldap=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --disable-ldap) ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ldap) ;; esac], - [enable_ldap=true] + [enable_ldap=false] ) -AM_CONDITIONAL(BUILD_LDAP, test x$enable_ldap != xfalse) if test "$enable_ldap" = "true"; then - AC_CHECK_LIB(ldap,ldap_initialize, LDAP_LIBS="-lldap") + AC_CHECK_LIB(sasl2, sasl_client_init , [foo=bar], + [AC_MSG_ERROR(You need SASL for LDAP support)] + ) + + AC_CHECK_LIB(ldap,ldap_initialize, LDAP_LIBS="-lldap -llber -lsasl2", + [AC_MSG_ERROR(You need libldap for LDAP support)] + ) + + AC_CHECK_HEADERS(ldap.h) + AC_CHECK_HEADERS(sasl/sasl.h) AC_SUBST(LDAP_LIBS) AC_DEFINE(BUILD_LDAP,1,[Defined if LDAP build option enabled]) fi +AM_CONDITIONAL(BUILD_LDAP, test x$enable_ldap != xfalse) dnl conditionnal build of console interface. AC_ARG_ENABLE(console_ui, diff --git a/gtk/linphone.h b/gtk/linphone.h index c77a02e6d..bec8e7591 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -73,8 +73,6 @@ void linphone_gtk_show_assistant(void); void linphone_gtk_close_assistant(void); LinphoneCore *linphone_gtk_get_core(void); -LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); -void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap); GtkWidget *linphone_gtk_get_main_window(); void linphone_gtk_display_something(GtkMessageType type,const gchar *message); void linphone_gtk_start_call(GtkWidget *button); @@ -97,6 +95,12 @@ int linphone_gtk_get_ui_config_int(const char *key, int def); void linphone_gtk_set_ui_config_int(const char *key , int val); void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show); +#ifdef BUILD_LDAP +LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); +void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap); +#endif + + void linphone_gtk_open_browser(const char *url); void linphone_gtk_check_for_new_version(void); const char *linphone_gtk_get_lang(const char *config_file); diff --git a/gtk/main.c b/gtk/main.c index db9568cb0..e39c37801 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -50,8 +50,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION; static LinphoneCore *the_core=NULL; -static LinphoneLDAPContactProvider* ldap_provider = NULL; static GtkWidget *the_ui=NULL; +#ifdef BUILD_LDAP +static LinphoneLDAPContactProvider* ldap_provider = NULL; +#endif 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); @@ -232,12 +234,9 @@ static const char *linphone_gtk_get_factory_config_file(){ return _factory_config_file; } -LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ #ifdef BUILD_LDAP +LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ return ldap_provider; -#else - return NULL; -#endif } void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) @@ -248,6 +247,7 @@ void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) ldap_provider = ldap ? LINPHONE_LDAP_CONTACT_PROVIDER(belle_sip_object_ref( ldap )) : NULL; } +#endif /* BUILD_LDAP */ static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file, const char *db_file) { @@ -751,6 +751,7 @@ static void completion_add_text(GtkEntry *entry, const char *text){ save_uri_history(); } +#ifdef BUILD_LDAP void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* friends, void* data ) { GtkTreeIter iter; @@ -853,6 +854,7 @@ static gboolean launch_contact_provider_search(void *userdata) } return FALSE; } +#endif /* BUILD_LDAP */ void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) { @@ -868,7 +870,7 @@ void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar); gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) ); -#endif +#endif /* BUILD_LDAP */ } bool_t linphone_gtk_video_enabled(void){ diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 20c0b01cd..53605f317 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -60,6 +60,7 @@ static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); } +#ifdef BUILD_LDAP static void linphone_gtk_ldap_load_settings(GtkWidget* param) { GtkWidget *mw = linphone_gtk_get_main_window(); @@ -185,6 +186,8 @@ void linphone_gtk_ldap_save(GtkWidget *tabmgr) lp_config_load_dict_to_section(conf, "ldap", dict); } +#endif /* BUILD_LDAP */ + void linphone_gtk_fill_video_sizes(GtkWidget *combo){ const MSVideoSizeDef *def=linphone_core_get_supported_video_sizes(linphone_gtk_get_core());; int i,active=0; From 08a7bf3be5f49703a4c128a01ff9c8950d1cb23c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 18 Dec 2013 16:31:00 +0100 Subject: [PATCH 059/439] improve mac bundle generation --- Makefile.am | 7 +------ README.macos | 32 +++++++++++++++++--------------- build/macos/environment.sh | 1 + 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Makefile.am b/Makefile.am index e9403361f..96ca6ee42 100644 --- a/Makefile.am +++ b/Makefile.am @@ -204,13 +204,9 @@ MACAPPNAME=Linphone.app MACAPPZIP=$(PACKAGE)-$(VERSION).app.zip BUNDLEPREFIX=./ BUNDLEDIR=$(BUNDLEPREFIX)$(MACAPPNAME) -LIBICONV_HACK=$(top_builddir)/build/macos/libiconv.2.dylib -$(LIBICONV_HACK): - cd $(top_builddir)/build/macos && \ - wget http://download-mirror.savannah.gnu.org/releases/linphone/misc/libiconv.2.dylib -bundle: $(LIBICONV_HACK) +bundle: rm -rf $(INSTALLDIR) $(MKDIR_P) $(INSTALLDIR) make install DESTDIR=$(INSTALLDIR) @@ -223,7 +219,6 @@ bundle: $(LIBICONV_HACK) > $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc cp -f $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig sed -e 's:@executable_path.*/::g' $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig > $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules - cp -f $(LIBICONV_HACK) $(BUNDLEDIR)/Contents/Resources/lib/. cd $(BUNDLEDIR)/.. && rm -f $(MACAPPZIP) && zip -r $(MACAPPZIP) $(MACAPPNAME) && cd - ### diff --git a/README.macos b/README.macos index 1713b7968..a9b3582a4 100644 --- a/README.macos +++ b/README.macos @@ -14,33 +14,31 @@ You need: +universal - Install build time dependencies - $ sudo port install automake autoconf libtool intltool + $ sudo port install automake autoconf libtool intltool wget cunit - Install some linphone dependencies with macports - $ sudo port install speex + $ sudo port install antlr3 speex libvpx readline sqlite3 libsoup openldap $ sudo port install ffmpeg-devel -gpl2 - $ sudo port install libvpx - $ sudo port install readline - - Install gtk. It is recommended to use the quartz backend for better integration. $ sudo port install gtk2 +quartz +no_x11 $ sudo port install gtk-osx-application -python27 $ sudo port install hicolor-icon-theme -- Install additional librairies required for wizard (linphone.org account creation assistant) - $ sudo port install libsoup - -- Install sqlite3 for message storage - $ sudo port install sqlite3 - -The softwares below need to be compiled manually. To ensure compatibility with multiple mac os version it is recommended to do: +The next pieces need to be compiled manually. To ensure compatibility with multiple mac os version it is recommended to do: $ export MACOSX_DEPLOYMENT_TARGET=10.6 $ export CFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export OBJCFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" +- Install libantlr3c (library used by belle-sip for parsing) + $ wget http://www.antlr3.org/download/C/libantlr3c-3.4.tar.gz + $ tar -xvzf libantlr3c-3.4.tar.gz + $ cd libantlr3c-3.4 + $ ./configure --disable-static --prefix=/opt/local --enable-64bit && make + $ sudo make install + - Install polarssl (encryption library used by belle-sip) $ git clone git://git.linphone.org/polarssl.git -b linphone $ cd polarssl @@ -54,8 +52,6 @@ The softwares below need to be compiled manually. To ensure compatibility with m $ sudo make install - Install srtp (optional) for call encryption - $ sudo port install srtp - If that fails, get from source: $ git clone git://git.linphone.org/srtp.git $ cd srtp && autoconf && ./configure --prefix=/opt/local && make libsrtp.a $ sudo make install @@ -104,6 +100,12 @@ Use git: #make this dummy charset.alias file for the bundler to be happy: $ sudo touch touch /opt/local/lib/charset.alias +The bundler file in build/macos/linphone.bundle expects some plugins to be installed in /opt/local/lib/mediastreamer/plugins . +If you don't need plugins, remove or comment out this line from the bundler file: + + ${prefix:ms2plugins}/lib/mediastreamer/plugins/*.*.so + + Then run, inside linphone source tree: Run configure as told before but with "--enable-relativeprefix" appended. $ make @@ -116,7 +118,7 @@ For a better appearance, you can install the gtk-quartz-engine (a gtk theme) tha $ git clone https://github.com/jralls/gtk-quartz-engine.git $ cd gtk-quartz-engine $ autoreconf -i - $ ./configure --prefix=/opt/local && make + $ ./configure --prefix=/opt/local CFLAGS="-Wno-error" && make $ sudo make install Generate a new bundle to have it included. diff --git a/build/macos/environment.sh b/build/macos/environment.sh index c2c672973..3b9ff16af 100644 --- a/build/macos/environment.sh +++ b/build/macos/environment.sh @@ -2,4 +2,5 @@ export EXTRA_ARGS="--workdir $bundle_res" export GIO_EXTRA_MODULES="$bundle_lib/gio/modules" export PANGO_LIBDIR="$bundle_lib" export PANGO_SYSCONFDIR="$bundle_etc" +export DYLD_LIBRARY_PATH= From e37cb37fecb051183be86c08f4d0cd53d9d2df01 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 19 Dec 2013 14:51:50 +0100 Subject: [PATCH 060/439] Moved contact provider internals to a private header. I also added lots of methods to manipulate Contact Providers --- coreapi/contact_providers_priv.h | 67 ++++++++++++++++++++++++++++++++ coreapi/contactprovider.c | 54 ++++++++++++++++++++++--- coreapi/contactprovider.h | 46 +++++++--------------- coreapi/ldap/ldapprovider.c | 29 +++++++++++++- coreapi/ldap/ldapprovider.h | 15 +++---- coreapi/linphonecore.c | 7 ---- coreapi/linphonecore.h | 9 ++++- 7 files changed, 168 insertions(+), 59 deletions(-) create mode 100644 coreapi/contact_providers_priv.h diff --git a/coreapi/contact_providers_priv.h b/coreapi/contact_providers_priv.h new file mode 100644 index 000000000..41b7bd327 --- /dev/null +++ b/coreapi/contact_providers_priv.h @@ -0,0 +1,67 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef CONTACT_PROVIDERS_PRIV_H +#define CONTACT_PROVIDERS_PRIV_H + +#include +#include "linphonecore.h" + +/* Base for contact search and contact provider */ + +struct _LinphoneContactSearch{ + belle_sip_object_t base; + ContactSearchID id; + char* predicate; + ContactSearchCallback cb; + void* data; +}; + +#define LINPHONE_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneContactSearch) +BELLE_SIP_DECLARE_VPTR(LinphoneContactSearch) + + +struct _LinphoneContactProvider { + belle_sip_object_t base; + LinphoneCore* lc; +}; + +#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneContactProvider) + +typedef LinphoneContactSearch* (*LinphoneContactProviderStartSearchMethod)( LinphoneContactProvider* thiz, const char* predicate, ContactSearchCallback cb, void* data ); +typedef unsigned int (*LinphoneContactProviderCancelSearchMethod)( LinphoneContactProvider* thiz, LinphoneContactSearch *request ); + +BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider,belle_sip_object_t) + const char* name; /*!< Name of the contact provider (LDAP, Google, ...) */ + + /* pure virtual methods: inheriting objects must implement these */ + LinphoneContactProviderStartSearchMethod begin_search; + LinphoneContactProviderCancelSearchMethod cancel_search; +BELLE_SIP_DECLARE_CUSTOM_VPTR_END + +/* LDAP search and contact providers */ + + +#define LINPHONE_LDAP_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactSearch) +BELLE_SIP_DECLARE_VPTR(LinphoneLDAPContactSearch) + +#define LINPHONE_LDAP_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactProvider) + +BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider,LinphoneContactProvider) +BELLE_SIP_DECLARE_CUSTOM_VPTR_END + + +#endif // CONTACT_PROVIDERS_PRIV_H diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index 835e8c62a..86541b2a3 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -14,11 +14,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "contact_providers_priv.h" #include "contactprovider.h" #include -/* LinphoneContactSearchRequest - */ +/* ############################ * + * LinphoneContactSearchRequest * + * ############################ */ void linphone_contact_search_init(LinphoneContactSearch* obj, const char* predicate, @@ -57,6 +59,21 @@ int linphone_contact_search_compare(const void* a, const void* b) { return !(ra->id == rb->id); // return 0 if id is equal, 1 otherwise } +LinphoneContactSearch*linphone_ldap_contact_search_ref(void* obj) +{ + return LINPHONE_CONTACT_SEARCH(belle_sip_object_ref(obj)); +} + +void linphone_ldap_contact_search_unref(void* obj) +{ + belle_sip_object_unref(obj); +} + +LinphoneContactSearch* linphone_contact_search_cast(void* obj) +{ + return LINPHONE_CONTACT_SEARCH(obj); +} + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactSearch); BELLE_SIP_INSTANCIATE_VPTR(LinphoneContactSearch,belle_sip_object_t, @@ -66,9 +83,11 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneContactSearch,belle_sip_object_t, FALSE ); -/* - * LinphoneContactProvider - */ + + +/* ####################### * + * LinphoneContactProvider * + * ####################### */ void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc){ @@ -79,6 +98,30 @@ static void contact_provider_destroy(LinphoneContactProvider* obj){ (void)obj; } +LinphoneContactSearch* linphone_contact_provider_begin_search(LinphoneContactProvider* obj, const char* predicate, ContactSearchCallback cb, void* data) +{ + return BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->begin_search( LINPHONE_CONTACT_PROVIDER(obj), predicate, cb, data); +} + +unsigned int linphone_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch* request) +{ + return BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->cancel_search( LINPHONE_CONTACT_PROVIDER(obj), request); +} + +LinphoneContactProvider* linphone_contact_provider_ref(void* obj) +{ + return LINPHONE_CONTACT_PROVIDER(belle_sip_object_ref(obj)); +} + +void linphone_contact_provider_unref(void* obj) +{ + belle_sip_object_unref(obj); +} + +LinphoneContactProvider*linphone_contact_provider_cast(void* obj) +{ + return LINPHONE_CONTACT_PROVIDER(obj); +} BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactProvider); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneContactProvider)= @@ -95,4 +138,3 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneContactProvider)= NULL /* cancel_search -> pure virtual */ }; - diff --git a/coreapi/contactprovider.h b/coreapi/contactprovider.h index 857bd1a8d..83cbee1b7 100644 --- a/coreapi/contactprovider.h +++ b/coreapi/contactprovider.h @@ -14,50 +14,30 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include #include "linphonecore.h" /* LinphoneContactSearchRequest */ -struct _LinphoneContactSearch{ - belle_sip_object_t base; - ContactSearchID id; - char* predicate; - ContactSearchCallback cb; - void* data; -}; - -#define LINPHONE_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneContactSearch) -BELLE_SIP_DECLARE_VPTR(LinphoneContactSearch) - - void linphone_contact_search_init(LinphoneContactSearch* obj, const char* predicate, ContactSearchCallback cb, void* cb_data); ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj); const char* linphone_contact_search_get_predicate(LinphoneContactSearch* obj); void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends); - +LinphoneContactSearch* linphone_contact_search_ref(void* obj); +void linphone_contact_search_unref(void* obj); +LinphoneContactSearch* linphone_contact_search_cast( void*obj ); /* LinphoneContactProvider */ -struct _LinphoneContactProvider { - belle_sip_object_t base; - LinphoneCore* lc; -}; - -typedef struct _LinphoneContactProvider LinphoneContactProvider; -typedef LinphoneContactSearch* (*LinphoneContactProviderStartSearchMethod)( LinphoneContactProvider* thiz, const char* predicate, ContactSearchCallback cb, void* data ); -typedef unsigned int (*LinphoneContactProviderCancelSearchMethod)( LinphoneContactProvider* thiz, LinphoneContactSearch *request ); -#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneContactProvider) - -BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider,belle_sip_object_t) - const char* name; /*!< Name of the contact provider (LDAP, Google, ...) */ - - /* pure virtual methods: inheriting objects must implement these */ - LinphoneContactProviderStartSearchMethod begin_search; - LinphoneContactProviderCancelSearchMethod cancel_search; -BELLE_SIP_DECLARE_CUSTOM_VPTR_END - - void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc); LinphoneCore* linphone_contact_provider_get_core(LinphoneContactProvider* obj); const char* linphone_contact_provider_get_name(LinphoneContactProvider* obj); +LinphoneContactProvider* linphone_contact_provider_ref(void* obj); +void linphone_contact_provider_unref(void* obj); +LinphoneContactProvider* linphone_contact_provider_cast( void*obj ); + +LinphoneContactSearch* linphone_contact_provider_begin_search(LinphoneContactProvider* obj, + const char* predicate, + ContactSearchCallback cb, + void* data); +unsigned int linphone_contact_provider_cancel_search(LinphoneContactProvider* obj, + LinphoneContactSearch* request); diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 2c783d6fa..ee8fb2720 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -18,6 +18,7 @@ #include "linphonecore.h" #include "linphonecore_utils.h" #include "lpconfig.h" +#include "contact_providers_priv.h" #include #include @@ -571,7 +572,7 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj } else { int err; ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err); - ms_error("ldap_sasl_bind error returned %d, err %d (%s), auth_method: %s", + ms_error("ldap_sasl_bind error returned %x, err %x (%s), auth_method: %s", ret, err, ldap_err2string(err), auth_mechanism ); } @@ -616,6 +617,10 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* belle_sip_object_unref(obj); obj = NULL; } else { + // prevents blocking calls to bind() when the server is invalid, but this is not working for now.. + // see bug https://bugzilla.mozilla.org/show_bug.cgi?id=79509 + ldap_set_option( obj->ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON); + // register our hook into iterate so that LDAP can do its magic asynchronously. linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); } @@ -740,6 +745,27 @@ static int linphone_ldap_contact_provider_marshal(LinphoneLDAPContactProvider* o } +LinphoneLDAPContactProvider*linphone_ldap_contact_provider_ref(void* obj) +{ + return linphone_ldap_contact_provider_cast(belle_sip_object_ref(obj)); +} + + +void linphone_ldap_contact_provider_unref(void* obj) +{ + belle_sip_object_unref(obj); +} + +inline LinphoneLDAPContactSearch*linphone_ldap_contact_search_cast(void* obj) +{ + return BELLE_SIP_CAST(obj, LinphoneLDAPContactSearch); +} + + +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast(void* obj) +{ + return BELLE_SIP_CAST(obj, LinphoneLDAPContactProvider); +} BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); @@ -758,3 +784,4 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= } }; + diff --git a/coreapi/ldap/ldapprovider.h b/coreapi/ldap/ldapprovider.h index 73878ee7c..0310a84bc 100644 --- a/coreapi/ldap/ldapprovider.h +++ b/coreapi/ldap/ldapprovider.h @@ -16,30 +16,25 @@ #include "contactprovider.h" -#include typedef struct _LinphoneLDAPContactProvider LinphoneLDAPContactProvider; /* LinphoneLDAPContactSearch */ typedef struct _LinphoneLDAPContactSearch LinphoneLDAPContactSearch; -#define LINPHONE_LDAP_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactSearch) -BELLE_SIP_DECLARE_VPTR(LinphoneLDAPContactSearch) - LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* ld, const char* predicate, ContactSearchCallback cb, void* cb_data); unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj); +LinphoneLDAPContactSearch* linphone_ldap_contact_search_cast( void* obj ); /* LinphoneLDAPContactProvider */ -#define LINPHONE_LDAP_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactProvider) - -BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider,LinphoneContactProvider) -BELLE_SIP_DECLARE_CUSTOM_VPTR_END - LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config); -unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj); +unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj); +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_ref( void* obj ); +void linphone_ldap_contact_provider_unref( void* obj ); +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj ); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 870512454..45c740a29 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5677,13 +5677,6 @@ static void linphone_core_uninit(LinphoneCore *lc) } #endif //BUILD_UPNP -#ifdef BUILD_LDAP - if( lc->ldap != NULL ) { - belle_sip_object_unref(lc->ldap); - lc->ldap = NULL; - } -#endif - 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 */ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 1e61cd37f..ab1af9c2a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2203,8 +2203,9 @@ LINPHONE_PUBLIC const char *linphone_core_get_video_display_filter(LinphoneCore LINPHONE_PUBLIC void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filtername); -/** Contact Providers +/** Belle Sip-based objects need unique ids */ + BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) BELLE_SIP_TYPE_ID(LinphoneContactSearch), BELLE_SIP_TYPE_ID(LinphoneContactProvider), @@ -2212,10 +2213,14 @@ BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) BELLE_SIP_DECLARE_TYPES_END + +/** Contact Providers + */ + typedef unsigned int ContactSearchID; -struct _LinphoneContactSearch; typedef struct _LinphoneContactSearch LinphoneContactSearch; +typedef struct _LinphoneContactProvider LinphoneContactProvider; typedef void (*ContactSearchCallback)( LinphoneContactSearch* id, MSList* friends, void* data ); From 317f0f08cccc12ade7fe3ec3195aeb73fe824a96 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 19 Dec 2013 15:24:05 +0100 Subject: [PATCH 061/439] Updated object macros from Belle Sip and stubbed LDAP implementation when LDAP support deactivated. --- coreapi/contactprovider.c | 5 ++-- coreapi/ldap/ldapprovider.c | 31 ++++++++++++++++++++--- coreapi/private.h | 8 ------ gtk/linphone.h | 6 ----- gtk/main.c | 49 ++++++++++++++----------------------- gtk/propertybox.c | 17 ++++++------- 6 files changed, 56 insertions(+), 60 deletions(-) diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index 86541b2a3..cd40887b1 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -124,8 +124,7 @@ LinphoneContactProvider*linphone_contact_provider_cast(void* obj) } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactProvider); -BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneContactProvider)= -{ +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider) { BELLE_SIP_VPTR_INIT(LinphoneContactProvider,belle_sip_object_t,TRUE), (belle_sip_object_destroy_t) contact_provider_destroy, @@ -136,5 +135,5 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneContactProvider)= // Pure virtual NULL, /* begin_search -> pure virtual */ NULL /* cancel_search -> pure virtual */ -}; +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index ee8fb2720..5b9ee97e6 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -24,6 +24,7 @@ #include #include +#ifdef BUILD_LDAP #define MAX_RUNNING_REQUESTS 10 #define FILTER_MAX_SIZE 512 @@ -769,8 +770,7 @@ LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast(void* obj) BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); -BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= -{ +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider) { { BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE), @@ -782,6 +782,31 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(LinphoneLDAPContactProvider)= (LinphoneContactProviderStartSearchMethod)linphone_ldap_contact_provider_begin_search, (LinphoneContactProviderCancelSearchMethod)linphone_ldap_contact_provider_cancel_search } -}; +BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END + +#else + +/* Stubbed implementation */ + +LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* ld, + const char* predicate, + ContactSearchCallback cb, + void* cb_data) +{ + return NULL; +} + +unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj){ return 0; } +LinphoneLDAPContactSearch* linphone_ldap_contact_search_cast( void* obj ){ return NULL; } +/* LinphoneLDAPContactProvider */ + +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config){ return NULL; } +unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj){ return 0; } +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_ref( void* obj ){ return NULL; } +void linphone_ldap_contact_provider_unref( void* obj ){ } +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj ){ return NULL; } + + +#endif /* BUILD_LDAP */ diff --git a/coreapi/private.h b/coreapi/private.h index 8f13716e1..69ee5b61e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -74,10 +74,6 @@ extern "C" { #endif #endif -#ifdef BUILD_LDAP -#include "ldap/ldapprovider.h" -#endif - 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 */ @@ -660,10 +656,6 @@ struct _LinphoneCore #ifdef BUILD_UPNP UpnpContext *upnp; #endif //BUILD_UPNP - -#ifdef BUILD_LDAP - LinphoneLDAPContactProvider* ldap; -#endif //BUILD_LDAP }; diff --git a/gtk/linphone.h b/gtk/linphone.h index bec8e7591..159cf2782 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -28,10 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "linphonecore.h" -#ifdef BUILD_LDAP #include "ldap/ldapprovider.h" -#endif - #ifdef ENABLE_NLS # include @@ -95,11 +92,8 @@ int linphone_gtk_get_ui_config_int(const char *key, int def); void linphone_gtk_set_ui_config_int(const char *key , int val); void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show); -#ifdef BUILD_LDAP LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap); -#endif - void linphone_gtk_open_browser(const char *url); void linphone_gtk_check_for_new_version(void); diff --git a/gtk/main.c b/gtk/main.c index e39c37801..10f6cb387 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -51,9 +51,7 @@ const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION; static LinphoneCore *the_core=NULL; static GtkWidget *the_ui=NULL; -#ifdef BUILD_LDAP static LinphoneLDAPContactProvider* ldap_provider = NULL; -#endif 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); @@ -234,7 +232,6 @@ static const char *linphone_gtk_get_factory_config_file(){ return _factory_config_file; } -#ifdef BUILD_LDAP LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ return ldap_provider; } @@ -242,12 +239,11 @@ LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) { if( ldap_provider ) - belle_sip_object_unref(ldap_provider); + linphone_contact_provider_unref(ldap_provider); - ldap_provider = ldap ? LINPHONE_LDAP_CONTACT_PROVIDER(belle_sip_object_ref( ldap )) + ldap_provider = ldap ? linphone_ldap_contact_provider_ref( ldap ) : NULL; } -#endif /* BUILD_LDAP */ static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file, const char *db_file) { @@ -276,13 +272,11 @@ static void linphone_gtk_init_liblinphone(const char *config_file, //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); -#ifdef BUILD_LDAP if( lp_config_has_section(linphone_core_get_config(the_core),"ldap") ){ LpConfig* cfg = linphone_core_get_config(the_core); LinphoneDictionary* ldap_cfg = lp_config_section_to_dict(cfg, "ldap"); linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(the_core, ldap_cfg) ); } -#endif linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION); linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL); @@ -751,7 +745,6 @@ static void completion_add_text(GtkEntry *entry, const char *text){ save_uri_history(); } -#ifdef BUILD_LDAP void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* friends, void* data ) { GtkTreeIter iter; @@ -759,6 +752,7 @@ void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* fri GtkEntryCompletion* compl = gtk_entry_get_completion(uribar); GtkTreeModel* model = gtk_entry_completion_get_model(compl); GtkListStore* list = GTK_LIST_STORE(model); + LinphoneLDAPContactSearch* search = linphone_ldap_contact_search_cast(req); gboolean valid; // clear completion list from previous non-history entries @@ -802,7 +796,7 @@ void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* fri // save the number of LDAP results to better decide if new results should be fetched when search predicate gets bigger gtk_object_set_data(GTK_OBJECT(uribar), "ldap_res_cout", GINT_TO_POINTER( - linphone_ldap_contact_search_result_count(LINPHONE_LDAP_CONTACT_SEARCH(req)) + linphone_ldap_contact_search_result_count(search) ) ); @@ -842,35 +836,32 @@ static gboolean launch_contact_provider_search(void *userdata) gtk_object_set_data(GTK_OBJECT(uribar), "previous_search", ms_strdup(predicate)); ms_message("launch_contact_provider_search"); - LinphoneContactSearch* search = - BELLE_SIP_OBJECT_VPTR(ldap,LinphoneContactProvider)->begin_search( - LINPHONE_CONTACT_PROVIDER(ldap), - predicate, - on_contact_provider_search_results, - uribar); + LinphoneContactSearch* search =linphone_contact_provider_begin_search( + linphone_contact_provider_cast(ldap_provider), + predicate, on_contact_provider_search_results, uribar + ); if(search) belle_sip_object_ref(search); } return FALSE; } -#endif /* BUILD_LDAP */ void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data) { -#ifdef BUILD_LDAP - gchar* text = gtk_editable_get_chars(uribar, 0,-1); - gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout")); - if( text ) g_free(text); + if( linphone_gtk_get_ldap() ) { + gchar* text = gtk_editable_get_chars(uribar, 0,-1); + gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout")); + if( text ) g_free(text); - if( timeout != 0 ) { - g_source_remove(timeout); + if( timeout != 0 ) { + g_source_remove(timeout); + } + + timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar); + + gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) ); } - - timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar); - - gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) ); -#endif /* BUILD_LDAP */ } bool_t linphone_gtk_video_enabled(void){ @@ -2046,9 +2037,7 @@ static void linphone_gtk_quit(void){ #ifdef BUILD_WIZARD linphone_gtk_close_assistant(); #endif -#ifdef BUILD_LDAP linphone_gtk_set_ldap(NULL); -#endif linphone_gtk_uninit_instance(); linphone_gtk_destroy_log_window(); linphone_core_destroy(the_core); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 53605f317..68cba2655 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -60,7 +60,6 @@ static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); } -#ifdef BUILD_LDAP static void linphone_gtk_ldap_load_settings(GtkWidget* param) { GtkWidget *mw = linphone_gtk_get_main_window(); @@ -186,8 +185,6 @@ void linphone_gtk_ldap_save(GtkWidget *tabmgr) lp_config_load_dict_to_section(conf, "ldap", dict); } -#endif /* BUILD_LDAP */ - void linphone_gtk_fill_video_sizes(GtkWidget *combo){ const MSVideoSizeDef *def=linphone_core_get_supported_video_sizes(linphone_gtk_get_core());; int i,active=0; @@ -1431,13 +1428,13 @@ void linphone_gtk_show_parameters(void){ } /* LDAP CONFIG */ -#ifdef BUILD_LDAP - linphone_gtk_ldap_load_settings(pb); -#else - // hide the LDAP tab - GtkNotebook* notebook = GTK_NOTEBOOK(linphone_gtk_get_widget(pb, "notebook1")); - gtk_notebook_remove_page(notebook,5); -#endif + if( linphone_gtk_get_ldap() ) { // if LDAP provider is available + linphone_gtk_ldap_load_settings(pb); + } else { + // hide the LDAP tab + GtkNotebook* notebook = GTK_NOTEBOOK(linphone_gtk_get_widget(pb, "notebook1")); + gtk_notebook_remove_page(notebook,5); + } gtk_widget_show(pb); } From e028749f116a68bc9222f6691f795603dae305d0 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 19 Dec 2013 15:58:24 +0100 Subject: [PATCH 062/439] Always compile ldap so that stubbed versions are supported --- coreapi/Makefile.am | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 7d728492a..a8987757d 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -49,16 +49,13 @@ liblinphone_la_SOURCES=\ info.c \ event.c event.h \ contactprovider.c contactprovider.h \ + ldap/ldapprovider.c ldap/ldapprovider.h \ dict.c \ $(GITVERSION_FILE) if BUILD_UPNP liblinphone_la_SOURCES+=upnp.c upnp.h endif - -if BUILD_LDAP -liblinphone_la_SOURCES+= ldap/ldapprovider.c ldap/ldapprovider.h -endif liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_impl.c bellesip_sal/sal_impl.h \ From 2f9d48a53f815a4e8e55f6eedba0b565341387ed Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 19 Dec 2013 16:28:12 +0100 Subject: [PATCH 063/439] Don't inlcude ldap.h when BUILD_LDAP is disabled --- coreapi/ldap/ldapprovider.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 5b9ee97e6..e9e5901b0 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -21,10 +21,11 @@ #include "contact_providers_priv.h" #include +#ifdef BUILD_LDAP + #include #include -#ifdef BUILD_LDAP #define MAX_RUNNING_REQUESTS 10 #define FILTER_MAX_SIZE 512 From eb93c8a62fce6707d9ee3d0d9a9714b568796f71 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 19 Dec 2013 17:22:24 +0100 Subject: [PATCH 064/439] fix crash when receiving SDP with many mlines --- coreapi/bellesip_sal/sal_sdp.c | 6 ++++++ oRTP | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index c01d1d83b..dd7794b26 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -315,6 +315,12 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S ; media_desc_it!=NULL ; media_desc_it=media_desc_it->next ) { int nb_ice_candidates=0; + + if (desc->n_total_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){ + ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->n_total_streams); + break; + } + media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); stream=&desc->streams[desc->n_total_streams]; media=belle_sdp_media_description_get_media ( media_desc ); diff --git a/oRTP b/oRTP index 123ef1a55..37b81a118 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 123ef1a55c321826966a3a375bee09b558ae170d +Subproject commit 37b81a118760caa22a5a89d56945acea9aa52523 From 97ccc1800273c7d1b620b87957bcae71ade41523 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 19 Dec 2013 17:30:05 +0100 Subject: [PATCH 065/439] add config.h inclusion --- coreapi/ldap/ldapprovider.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index e9e5901b0..69710c5d3 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -15,14 +15,12 @@ */ #include "ldapprovider.h" -#include "linphonecore.h" -#include "linphonecore_utils.h" +#include "private.h" #include "lpconfig.h" #include "contact_providers_priv.h" #include #ifdef BUILD_LDAP - #include #include From 1b7e52c1ecae7b5854e0d9e603659e8f246ef0ea Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 19 Dec 2013 22:42:54 +0100 Subject: [PATCH 066/439] add opus to README.macos --- README.macos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.macos b/README.macos index a9b3582a4..01f1880e4 100644 --- a/README.macos +++ b/README.macos @@ -17,7 +17,7 @@ You need: $ sudo port install automake autoconf libtool intltool wget cunit - Install some linphone dependencies with macports - $ sudo port install antlr3 speex libvpx readline sqlite3 libsoup openldap + $ sudo port install antlr3 speex opus libvpx readline sqlite3 libsoup openldap $ sudo port install ffmpeg-devel -gpl2 - Install gtk. It is recommended to use the quartz backend for better integration. From d777e00ac9b91c1d05d438bd466113b0366500fc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Dec 2013 10:38:59 +0100 Subject: [PATCH 067/439] change behavior of LinphoneCall::camera_enabled It is now an application preference, the core never modifies it. It represents whether the camera is allowed to be sent (in case of video request). --- coreapi/callbacks.c | 2 +- coreapi/conference.c | 2 +- coreapi/linphonecall.c | 13 ++++++------- coreapi/linphonecore.c | 6 ++---- coreapi/private.h | 2 +- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e73a60fa9..a9c364c52 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -98,7 +98,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if (call->audiostream) linphone_core_enable_mic(lc, linphone_core_mic_enabled(lc)); #ifdef VIDEO_ENABLED - if (call->videostream && call->camera_active) + if (call->videostream && call->camera_enabled) video_stream_change_camera(call->videostream,lc->video_conf.device ); #endif } diff --git a/coreapi/conference.c b/coreapi/conference.c index 53d3edf40..2e5c2ccde 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -99,7 +99,7 @@ void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted){ LinphoneConference *conf=&lc->conf_ctx; MSAudioEndpoint *ep; call->params.has_video = FALSE; - call->camera_active = FALSE; + call->camera_enabled = FALSE; ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE); ms_audio_conference_add_member(conf->conf,ep); ms_audio_conference_mute_member(conf->conf,ep,muted); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 19caa2059..fe0df1221 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -438,6 +438,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->media_start_time=0; call->log=linphone_call_log_new(call, from, to); call->owns_call_log=TRUE; + call->camera_enabled=TRUE; linphone_core_get_audio_port_range(call->core, &min_port, &max_port); if (min_port == max_port) { @@ -544,7 +545,6 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr } } #endif //BUILD_UPNP - call->camera_active=params->has_video; discover_mtu(lc,linphone_address_get_domain (to)); if (params->referer){ @@ -641,7 +641,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro default: break; } - call->camera_active=call->params.has_video; discover_mtu(lc,linphone_address_get_domain(from)); return call; @@ -1084,12 +1083,12 @@ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){ if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){ LinphoneCore *lc=call->core; MSWebCam *nowebcam=get_nowebcam_device(); - if (call->camera_active!=enable && lc->video_conf.device!=nowebcam){ + if (call->camera_enabled!=enable && lc->video_conf.device!=nowebcam){ video_stream_change_camera(call->videostream, enable ? lc->video_conf.device : nowebcam); } } - call->camera_active=enable; + call->camera_enabled=enable; #endif } @@ -1120,10 +1119,10 @@ int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file){ } /** - * Returns TRUE if camera pictures are sent to the remote party. + * Returns TRUE if camera pictures are allowed to be sent to the remote party. **/ bool_t linphone_call_camera_enabled (const LinphoneCall *call){ - return call->camera_active; + return call->camera_enabled; } /** @@ -1849,7 +1848,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna /*either inactive or incompatible with local capabilities*/ is_inactive=TRUE; } - if (call->camera_active==FALSE || all_inputs_muted){ + if (call->camera_enabled==FALSE || all_inputs_muted){ cam=get_nowebcam_device(); } if (!is_inactive){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 45c740a29..104925d51 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2964,7 +2964,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ const char *subject; - call->camera_active=call->params.has_video; + if (call->ice_session != NULL) { linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); } @@ -3065,7 +3065,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho #ifdef VIDEO_ENABLED if ((call->videostream != NULL) && (call->state == LinphoneCallStreamsRunning)) { video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); - if (call->camera_active && call->videostream->cam!=lc->video_conf.device){ + if (call->camera_enabled && call->videostream->cam!=lc->video_conf.device){ video_stream_change_camera(call->videostream,lc->video_conf.device); }else video_stream_update_video_params(call->videostream); } @@ -3177,7 +3177,6 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const call->params.has_video = FALSE; } call->params.has_video &= linphone_core_media_description_contains_video_stream(remote_desc); - call->camera_active=call->params.has_video; linphone_call_make_local_media_description(lc,call); if (call->ice_session != NULL) { linphone_core_update_ice_from_remote_media_description(call, remote_desc); @@ -3298,7 +3297,6 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, // There might not be a md if the INVITE was lacking an SDP // In this case we use the parameters as is. if (md) call->params.has_video &= linphone_core_media_description_contains_video_stream(md); - call->camera_active=call->params.has_video; linphone_call_make_local_media_description(lc,call); sal_call_set_local_media_description(call->op,call->localdesc); } diff --git a/coreapi/private.h b/coreapi/private.h index 69ee5b61e..5225b6a3c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -205,7 +205,7 @@ struct _LinphoneCall bool_t refer_pending; bool_t media_pending; bool_t audio_muted; - bool_t camera_active; + bool_t camera_enabled; bool_t all_muted; /*this flag is set during early medias*/ bool_t playing_ringbacktone; From 233c33bed22a6e8dd1dc86c026583ba9e5a9d1ad Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Dec 2013 11:43:32 +0100 Subject: [PATCH 068/439] update README --- README.macos | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/README.macos b/README.macos index 01f1880e4..76fa6ef83 100644 --- a/README.macos +++ b/README.macos @@ -33,10 +33,10 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" - Install libantlr3c (library used by belle-sip for parsing) - $ wget http://www.antlr3.org/download/C/libantlr3c-3.4.tar.gz - $ tar -xvzf libantlr3c-3.4.tar.gz - $ cd libantlr3c-3.4 - $ ./configure --disable-static --prefix=/opt/local --enable-64bit && make + $ git clone -b linphone git://git.linphone.org/antlr3.git + $ cd antlr3/runtime/C + $ ./autogen.sh + $ ./configure --disable-static --prefix=/opt/local && make $ sudo make install - Install polarssl (encryption library used by belle-sip) @@ -62,14 +62,6 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make $ sudo make install - ** WARNING 2013-03-06 glib-networking is currently broken in macports - generates crashes or hangs when used in a bundle ** - As a temporary workaround, build a newer version by yourself: - $ wget http://ftp.gnome.org/pub/gnome/sources/glib-networking/2.34/glib-networking-2.34.2.tar.xz - $ tar -xvzf glib-networking-2.34.2.tar.xz - $ cd glib-networking-2.34.2 - $ ./configure --prefix=/opt/local --without-ca-certificates && make - $ sudo make install - - Compile and install the tunnel library (optional, proprietary extension only) If you got the source code from git, run ./autogen.sh first From 863ccb24fa353ce3242634700fc8169e258aa32b Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 20 Dec 2013 11:46:13 +0100 Subject: [PATCH 069/439] Fix missing header in Makefile.am --- coreapi/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index a8987757d..3933ddb05 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -48,7 +48,7 @@ liblinphone_la_SOURCES=\ message_storage.c \ info.c \ event.c event.h \ - contactprovider.c contactprovider.h \ + contactprovider.c contactprovider.h contact_providers_priv.h \ ldap/ldapprovider.c ldap/ldapprovider.h \ dict.c \ $(GITVERSION_FILE) From 6d989a42609d48fd5b9e5aad941e1a960dccbf48 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 20 Dec 2013 11:49:15 +0100 Subject: [PATCH 070/439] Correct ldap support check. --- coreapi/ldap/ldapprovider.c | 8 ++++++++ coreapi/ldap/ldapprovider.h | 3 ++- gtk/linphone.h | 2 ++ gtk/main.c | 4 ++++ gtk/propertybox.c | 2 +- 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 69710c5d3..6bdfa072a 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -767,6 +767,11 @@ LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast(void* obj) return BELLE_SIP_CAST(obj, LinphoneLDAPContactProvider); } +int linphone_ldap_contact_provider_available() +{ + return 1; +} + BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider) @@ -807,5 +812,8 @@ LinphoneLDAPContactProvider* linphone_ldap_contact_provider_ref( void* obj ){ re void linphone_ldap_contact_provider_unref( void* obj ){ } LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj ){ return NULL; } +int linphone_ldap_contact_provider_available(){ return 0; } + #endif /* BUILD_LDAP */ + diff --git a/coreapi/ldap/ldapprovider.h b/coreapi/ldap/ldapprovider.h index 0310a84bc..0c95f7511 100644 --- a/coreapi/ldap/ldapprovider.h +++ b/coreapi/ldap/ldapprovider.h @@ -37,4 +37,5 @@ LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj); LinphoneLDAPContactProvider* linphone_ldap_contact_provider_ref( void* obj ); void linphone_ldap_contact_provider_unref( void* obj ); -LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj ); +LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj ); +int linphone_ldap_contact_provider_available(); diff --git a/gtk/linphone.h b/gtk/linphone.h index 159cf2782..1d674f876 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -94,6 +94,8 @@ void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, G LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap); +int linphone_gtk_is_ldap_supported(void); + void linphone_gtk_open_browser(const char *url); void linphone_gtk_check_for_new_version(void); diff --git a/gtk/main.c b/gtk/main.c index 10f6cb387..a25b42523 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -236,6 +236,10 @@ LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){ return ldap_provider; } +int linphone_gtk_is_ldap_supported(void){ + return linphone_ldap_contact_provider_available(); +} + void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) { if( ldap_provider ) diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 68cba2655..57f3b0c4e 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1428,7 +1428,7 @@ void linphone_gtk_show_parameters(void){ } /* LDAP CONFIG */ - if( linphone_gtk_get_ldap() ) { // if LDAP provider is available + if( linphone_gtk_is_ldap_supported() ) { // if LDAP provider is available linphone_gtk_ldap_load_settings(pb); } else { // hide the LDAP tab From 9938815efff6f5f2385730f857cb008ed0c39c9c Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 20 Dec 2013 12:01:47 +0100 Subject: [PATCH 071/439] Update mediastreamer 2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6920f363d..1451d9c76 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6920f363d8f6db7c98f6dc471a045f43e4f26200 +Subproject commit 1451d9c76af5741f89d21bc96ab40032647ffa7a From e8d63aa3bae0a13788fdb09a9499190eb406f4c3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Dec 2013 14:01:58 +0100 Subject: [PATCH 072/439] remove uri headers from Contact --- coreapi/bellesip_sal/sal_address_impl.c | 5 ++++- coreapi/proxy.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 01a5b6229..f73a06240 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -123,7 +123,10 @@ void sal_address_set_port(SalAddress *addr, int port){ void sal_address_clean(SalAddress *addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); belle_sip_uri_t* uri=belle_sip_header_address_get_uri(header_addr); - if (uri) belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(uri)); + if (uri) { + belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(uri)); + belle_sip_uri_headers_clean(uri); + } belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(header_addr)); return ; } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index d5bbe3e47..ade9e3a52 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -289,6 +289,8 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ int localport = -1; const char *localip = NULL; LinphoneAddress *contact=linphone_address_new(obj->reg_identity); + + linphone_address_clean(contact); if (obj->contact_params) { // We want to add a list of contacts params to the linphone address From ef29131c4079d4a75428b0f62242c139043fa6ca Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Dec 2013 14:54:39 +0100 Subject: [PATCH 073/439] fix unused variable --- coreapi/proxy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index ade9e3a52..214aabea8 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -302,7 +302,6 @@ 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); } From 0dc3eae678aad5957340036ae3d6939679f580d1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 20 Dec 2013 15:03:40 +0100 Subject: [PATCH 074/439] update README --- README.macos | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.macos b/README.macos index 76fa6ef83..db01b4869 100644 --- a/README.macos +++ b/README.macos @@ -62,10 +62,16 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make $ sudo make install + +- Install gsm codec (optional) + $ git clone git://git.linphone.org/gsm.git + $ cd gsm + $ make CCFLAGS="$CFLAGS -c -O2 -DNeedFunctionPrototypes=1" + $ sudo make install INSTALL_ROOT=/opt/local GSM_INSTALL_INC=/opt/local/include + - Compile and install the tunnel library (optional, proprietary extension only) - If you got the source code from git, run ./autogen.sh first - + If you got the source code from git, run ./autogen.sh first. Then or otherwise, do: $ ./configure --prefix=/opt/local && make && sudo make install @@ -110,7 +116,7 @@ For a better appearance, you can install the gtk-quartz-engine (a gtk theme) tha $ git clone https://github.com/jralls/gtk-quartz-engine.git $ cd gtk-quartz-engine $ autoreconf -i - $ ./configure --prefix=/opt/local CFLAGS="-Wno-error" && make + $ ./configure --prefix=/opt/local CFLAGS="$CFLAGS -Wno-error" && make $ sudo make install Generate a new bundle to have it included. From a8b47c508f1d8d87c9e9bae654e4909441e52553 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Dec 2013 16:30:17 +0100 Subject: [PATCH 075/439] Add missing symbol exports. --- coreapi/linphonecall.c | 4 +- coreapi/linphonecore.h | 108 ++++++++++++++++++------------------- coreapi/linphonepresence.h | 40 +++++++------- coreapi/lpconfig.h | 4 +- 4 files changed, 78 insertions(+), 78 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index fe0df1221..4510ef12f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1092,16 +1092,16 @@ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){ #endif } -#ifdef VIDEO_ENABLED /** * Request remote side to send us a Video Fast Update. **/ void linphone_call_send_vfu_request(LinphoneCall *call) { +#ifdef VIDEO_ENABLED if (LinphoneCallStreamsRunning == linphone_call_get_state(call)) sal_call_send_vfu_request(call->op); -} #endif +} /** diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index ab1af9c2a..c6a3332df 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -226,10 +226,10 @@ void lp_config_load_dict_to_section( LpConfig* lpconfig, const char* section, co #endif LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *addr); -LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr); -LinphoneAddress * linphone_address_ref(LinphoneAddress *addr); -void linphone_address_unref(LinphoneAddress *addr); -const char *linphone_address_get_scheme(const LinphoneAddress *u); +LINPHONE_PUBLIC LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr); +LINPHONE_PUBLIC LinphoneAddress * linphone_address_ref(LinphoneAddress *addr); +LINPHONE_PUBLIC void linphone_address_unref(LinphoneAddress *addr); +LINPHONE_PUBLIC const char *linphone_address_get_scheme(const LinphoneAddress *u); LINPHONE_PUBLIC const char *linphone_address_get_display_name(const LinphoneAddress* u); LINPHONE_PUBLIC const char *linphone_address_get_username(const LinphoneAddress *u); LINPHONE_PUBLIC const char *linphone_address_get_domain(const LinphoneAddress *u); @@ -615,7 +615,7 @@ LINPHONE_PUBLIC const char *linphone_call_state_to_string(LinphoneCallState cs); LINPHONE_PUBLIC LinphoneCore *linphone_call_get_core(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCallState linphone_call_get_state(const LinphoneCall *call); -bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneAddress * linphone_core_get_current_call_remote_address(LinphoneCore *lc); LINPHONE_PUBLIC const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); LINPHONE_PUBLIC char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); @@ -796,7 +796,7 @@ LINPHONE_PUBLIC const char* linphone_proxy_config_get_contact_uri_parameters(con * @param[in] obj #LinphoneProxyConfig object. * @returns The #LinphoneCore object to which is associated the #LinphoneProxyConfig. **/ -LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg); LINPHONE_PUBLIC const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg); @@ -806,7 +806,7 @@ LINPHONE_PUBLIC const char * linphone_proxy_config_get_dial_prefix(const Linphon * @param[in] cfg #LinphoneProxyConfig object. * @returns The reason why registration failed for this proxy config. **/ -LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg); /* * return the transport from either : service route, route, or addr @@ -817,10 +817,10 @@ LINPHONE_PUBLIC const char* linphone_proxy_config_get_transport(const LinphonePr /* destruction is called automatically when removing the proxy config */ -void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg); -void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type); +LINPHONE_PUBLIC void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type); SipSetupContext *linphone_proxy_config_get_sip_setup_context(LinphoneProxyConfig *cfg); -SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg); /** * normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222 */ @@ -922,8 +922,8 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_domain(const LinphoneAuthInfo LINPHONE_PUBLIC const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i); /* you don't need those function*/ -void linphone_auth_info_destroy(LinphoneAuthInfo *info); -LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos); +LINPHONE_PUBLIC void linphone_auth_info_destroy(LinphoneAuthInfo *info); +LINPHONE_PUBLIC LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos); struct _LinphoneChatRoom; @@ -1379,8 +1379,8 @@ LINPHONE_PUBLIC const char *linphone_core_get_primary_contact(LinphoneCore *lc); LINPHONE_PUBLIC const char * linphone_core_get_identity(LinphoneCore *lc); -void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val); -bool_t linphone_core_get_guess_hostname(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_get_guess_hostname(LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_ipv6_enabled(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val); @@ -1394,8 +1394,8 @@ LINPHONE_PUBLIC void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw LINPHONE_PUBLIC int linphone_core_get_download_bandwidth(const LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_get_upload_bandwidth(const LinphoneCore *lc); -void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled); -bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled); +LINPHONE_PUBLIC bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime); LINPHONE_PUBLIC int linphone_core_get_download_ptime(LinphoneCore *lc); @@ -1423,11 +1423,11 @@ LINPHONE_PUBLIC bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc); /* returns a MSList of PayloadType */ LINPHONE_PUBLIC const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); -int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs); +LINPHONE_PUBLIC int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs); /* returns a MSList of PayloadType */ LINPHONE_PUBLIC const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); -int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); +LINPHONE_PUBLIC int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); /** * Tells whether the specified payload type is enabled. @@ -1529,7 +1529,7 @@ LINPHONE_PUBLIC void linphone_core_clear_all_auth_info(LinphoneCore *lc); * @param[in] enable TRUE to enable the audio adaptive jitter compensation, FALSE to disable it. * @ingroup media_parameters */ -void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); +LINPHONE_PUBLIC void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); /** * Tells whether the audio adaptive jitter compensation is enabled. @@ -1537,11 +1537,11 @@ void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enabl * @returns TRUE if the audio adaptive jitter compensation is enabled, FALSE otherwise. * @ingroup media_parameters */ -bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore *lc); -int linphone_core_get_audio_jittcomp(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_audio_jittcomp(LinphoneCore *lc); -void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value); +LINPHONE_PUBLIC void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value); /** * Enable or disable the video adaptive jitter compensation. @@ -1549,7 +1549,7 @@ void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value); * @param[in] enable TRUE to enable the video adaptive jitter compensation, FALSE to disable it. * @ingroup media_parameters */ -void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); +LINPHONE_PUBLIC void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enable); /** * Tells whether the video adaptive jitter compensation is enabled. @@ -1557,11 +1557,11 @@ void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enabl * @returns TRUE if the video adaptive jitter compensation is enabled, FALSE otherwise. * @ingroup media_parameters */ -bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore *lc); -int linphone_core_get_video_jittcomp(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_video_jittcomp(LinphoneCore *lc); -void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value); +LINPHONE_PUBLIC void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value); LINPHONE_PUBLIC int linphone_core_get_audio_port(const LinphoneCore *lc); @@ -1642,7 +1642,7 @@ LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *l * * @return true if uPnP is available otherwise return false. */ -bool_t linphone_core_upnp_available(); +LINPHONE_PUBLIC bool_t linphone_core_upnp_available(); /** * @ingroup network_parameters @@ -1651,7 +1651,7 @@ bool_t linphone_core_upnp_available(); * @param lc #LinphoneCore * @return an LinphoneUpnpState. */ -LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); /** * @ingroup network_parameters @@ -1663,7 +1663,7 @@ LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); * @return a null terminated string containing the external ip address. If the * the external ip address is not available return null. */ -const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc); /** * Set the public IP address of NAT when using the firewall policy is set to use NAT. @@ -1671,7 +1671,7 @@ const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc); * @param[in] addr The public IP address of NAT to use. * @ingroup network_parameters */ -void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); +LINPHONE_PUBLIC void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); /** * Get the public IP address of NAT being used. @@ -1679,7 +1679,7 @@ void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); * @returns The public IP address of NAT being used. * @ingroup network_parameters */ -const char *linphone_core_get_nat_address(const LinphoneCore *lc); +LINPHONE_PUBLIC const char *linphone_core_get_nat_address(const LinphoneCore *lc); /** * Set the policy to use to pass through firewalls. @@ -1699,7 +1699,7 @@ LINPHONE_PUBLIC LinphoneFirewallPolicy linphone_core_get_firewall_policy(const L /* sound functions */ /* returns a null terminated static array of string describing the sound devices */ -const char** linphone_core_get_sound_devices(LinphoneCore *lc); +LINPHONE_PUBLIC const char** linphone_core_get_sound_devices(LinphoneCore *lc); /** * Update detection of sound devices. @@ -1709,13 +1709,13 @@ const char** linphone_core_get_sound_devices(LinphoneCore *lc); * @param[in] lc #LinphoneCore object. * @ingroup media_parameters **/ -void linphone_core_reload_sound_devices(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_reload_sound_devices(LinphoneCore *lc); -bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *device); -bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *device); +LINPHONE_PUBLIC bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *device); +LINPHONE_PUBLIC bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *device); LINPHONE_PUBLIC int linphone_core_get_ring_level(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_get_play_level(LinphoneCore *lc); -int linphone_core_get_rec_level(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_rec_level(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_ring_level(LinphoneCore *lc, int level); LINPHONE_PUBLIC void linphone_core_set_play_level(LinphoneCore *lc, int level); @@ -1724,13 +1724,13 @@ LINPHONE_PUBLIC float linphone_core_get_mic_gain_db(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_playback_gain_db(LinphoneCore *lc, float level); LINPHONE_PUBLIC float linphone_core_get_playback_gain_db(LinphoneCore *lc); -void linphone_core_set_rec_level(LinphoneCore *lc, int level); -const char * linphone_core_get_ringer_device(LinphoneCore *lc); -const char * linphone_core_get_playback_device(LinphoneCore *lc); -const char * linphone_core_get_capture_device(LinphoneCore *lc); -int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid); -int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid); -int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid); +LINPHONE_PUBLIC void linphone_core_set_rec_level(LinphoneCore *lc, int level); +LINPHONE_PUBLIC const char * linphone_core_get_ringer_device(LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_playback_device(LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_capture_device(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid); +LINPHONE_PUBLIC int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid); +LINPHONE_PUBLIC int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid); char linphone_core_get_sound_source(LinphoneCore *lc); void linphone_core_set_sound_source(LinphoneCore *lc, char source); LINPHONE_PUBLIC void linphone_core_stop_ringing(LinphoneCore *lc); @@ -1907,8 +1907,8 @@ LINPHONE_PUBLIC void linphone_core_set_preferred_video_size(LinphoneCore *lc, MS LINPHONE_PUBLIC MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name); -void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val); -bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val); LINPHONE_PUBLIC bool_t linphone_core_self_view_enabled(const LinphoneCore *lc); @@ -1922,7 +1922,7 @@ LINPHONE_PUBLIC bool_t linphone_core_self_view_enabled(const LinphoneCore *lc); * @param[in] lc #LinphoneCore object. * @ingroup media_parameters **/ -void linphone_core_reload_video_devices(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_reload_video_devices(LinphoneCore *lc); /* returns a null terminated static array of string describing the webcams */ LINPHONE_PUBLIC const char** linphone_core_get_video_devices(const LinphoneCore *lc); @@ -1936,7 +1936,7 @@ LINPHONE_PUBLIC const char *linphone_core_get_video_device(const LinphoneCore *l * @param[in] path The path to the image file to use. * @ingroup media_parameters */ -int linphone_core_set_static_picture(LinphoneCore *lc, const char *path); +LINPHONE_PUBLIC int linphone_core_set_static_picture(LinphoneCore *lc, const char *path); /** * Get the path to the image file streamed when "Static picture" is set as the video device. @@ -1944,7 +1944,7 @@ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path); * @returns The path to the image file streamed when "Static picture" is set as the video device. * @ingroup media_parameters */ -const char *linphone_core_get_static_picture(LinphoneCore *lc); +LINPHONE_PUBLIC const char *linphone_core_get_static_picture(LinphoneCore *lc); /** * Set the frame rate for static picture. @@ -1952,7 +1952,7 @@ const char *linphone_core_get_static_picture(LinphoneCore *lc); * @param[in] fps The new frame rate to use for static picture. * @ingroup media_parameters */ -int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps); +LINPHONE_PUBLIC int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps); /** * Get the frame rate for static picture @@ -1960,7 +1960,7 @@ int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps); * @return The frame rate used for static picture. * @ingroup media_parameters */ -float linphone_core_get_static_picture_fps(LinphoneCore *lc); +LINPHONE_PUBLIC float linphone_core_get_static_picture_fps(LinphoneCore *lc); /*function to be used for eventually setting window decorations (icons, title...)*/ LINPHONE_PUBLIC unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc); @@ -1998,7 +1998,7 @@ void linphone_core_show_video(LinphoneCore *lc, bool_t show); /*play/record support: use files instead of soundcard*/ void linphone_core_use_files(LinphoneCore *lc, bool_t yesno); LINPHONE_PUBLIC void linphone_core_set_play_file(LinphoneCore *lc, const char *file); -void linphone_core_set_record_file(LinphoneCore *lc, const char *file); +LINPHONE_PUBLIC void linphone_core_set_record_file(LinphoneCore *lc, const char *file); LINPHONE_PUBLIC void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); LINPHONE_PUBLIC void linphone_core_stop_dtmf(LinphoneCore *lc); @@ -2006,7 +2006,7 @@ LINPHONE_PUBLIC void linphone_core_stop_dtmf(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_get_current_call_duration(const LinphoneCore *lc); -int linphone_core_get_mtu(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_mtu(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_mtu(LinphoneCore *lc, int mtu); /** @@ -2091,7 +2091,7 @@ LINPHONE_PUBLIC void linphone_core_refresh_registers(LinphoneCore* lc); * @param[in] file The path to the file to use to store the zrtp secrets cache. * @ingroup initializing */ -void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file); +LINPHONE_PUBLIC void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file); /** * Get the path to the file storing the zrtp secrets cache. @@ -2099,7 +2099,7 @@ void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file); * @returns The path to the file storing the zrtp secrets cache. * @ingroup initializing */ -const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); +LINPHONE_PUBLIC const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); /** * Search from the list of current calls if a remote address match uri diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index dd2045262..851ccf63e 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -731,140 +731,140 @@ LINPHONE_PUBLIC int linphone_presence_note_set_lang(LinphonePresenceNote *note, * @param[in] model The #LinphonePresenceModel object for which the reference count is to be increased. * @return The #LinphonePresenceModel object with the increased reference count. */ -LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model); +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model); /** * Decrease the reference count of the #LinphonePresenceModel object and destroy it if it reaches 0. * @param[in] model The #LinphonePresenceModel object for which the reference count is to be decreased. * @return The #LinphonePresenceModel object if the reference count is still positive, NULL if the object has been destroyed. */ -LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model); +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model); /** * Sets the user data of a #LinphonePresenceModel object. * @param[in] model The #LinphonePresenceModel object for which to set the user data. * @param[in] user_data A pointer to the user data to set. */ -void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data); +LINPHONE_PUBLIC void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data); /** * Gets the user data of a #LinphonePresenceModel object. * @param[in] model The #LinphonePresenceModel object for which to get the user data. * @return A pointer to the user data. */ -void * linphone_presence_model_get_user_data(LinphonePresenceModel *model); +LINPHONE_PUBLIC void * linphone_presence_model_get_user_data(LinphonePresenceModel *model); /** * Increase the reference count of the #LinphonePresenceService object. * @param[in] service The #LinphonePresenceService object for which the reference count is to be increased. * @return The #LinphonePresenceService object with the increased reference count. */ -LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service); +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service); /** * Decrease the reference count of the #LinphonePresenceService object and destroy it if it reaches 0. * @param[in] service The #LinphonePresenceService object for which the reference count is to be decreased. * @return The #LinphonePresenceService object if the reference count is still positive, NULL if the object has been destroyed. */ -LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service); +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service); /** * Sets the user data of a #LinphonePresenceService object. * @param[in] service The #LinphonePresenceService object for which to set the user data. * @param[in] user_data A pointer to the user data to set. */ -void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data); +LINPHONE_PUBLIC void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data); /** * Gets the user data of a #LinphonePresenceService object. * @param[in] service The #LinphonePresenceService object for which to get the user data. * @return A pointer to the user data. */ -void * linphone_presence_service_get_user_data(LinphonePresenceService *service); +LINPHONE_PUBLIC void * linphone_presence_service_get_user_data(LinphonePresenceService *service); /** * Increase the reference count of the #LinphonePresencePerson object. * @param[in] person The #LinphonePresencePerson object for which the reference count is to be increased. * @return The #LinphonePresencePerson object with the increased reference count. */ -LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person); +LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person); /** * Decrease the reference count of the #LinphonePresencePerson object and destroy it if it reaches 0. * @param[in] person The #LinphonePresencePerson object for which the reference count is to be decreased. * @return The #LinphonePresencePerson object if the reference count is still positive, NULL if the object has been destroyed. */ -LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person); +LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person); /** * Sets the user data of a #LinphonePresencePerson object. * @param[in] person The #LinphonePresencePerson object for which to set the user data. * @param[in] user_data A pointer to the user data to set. */ -void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data); +LINPHONE_PUBLIC void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data); /** * Gets the user data of a #LinphonePresencePerson object. * @param[in] person The #LinphonePresencePerson object for which to get the user data. * @return A pointer to the user data. */ -void * linphone_presence_person_get_user_data(LinphonePresencePerson *person); +LINPHONE_PUBLIC void * linphone_presence_person_get_user_data(LinphonePresencePerson *person); /** * Increase the reference count of the #LinphonePresenceActivity object. * @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be increased. * @return The #LinphonePresenceActivity object with the increased reference count. */ -LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity); +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity); /** * Decrease the reference count of the #LinphonePresenceActivity object and destroy it if it reaches 0. * @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be decreased. * @return The #LinphonePresenceActivity object if the reference count is still positive, NULL if the object has been destroyed. */ -LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity); +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity); /** * Sets the user data of a #LinphonePresenceActivity object. * @param[in] activity The #LinphonePresenceActivity object for which to set the user data. * @param[in] user_data A pointer to the user data to set. */ -void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data); +LINPHONE_PUBLIC void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data); /** * Gets the user data of a #LinphonePresenceActivity object. * @param[in] activity The #LinphonePresenceActivity object for which to get the user data. * @return A pointer to the user data. */ -void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity); +LINPHONE_PUBLIC void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity); /** * Increase the reference count of the #LinphonePresenceNote object. * @param[in] note The #LinphonePresenceNote object for which the reference count is to be increased. * @return The #LinphonePresenceNote object with the increased reference count. */ -LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note); +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note); /** * Decrease the reference count of the #LinphonePresenceNote object and destroy it if it reaches 0. * @param[in] note The #LinphonePresenceNote object for which the reference count is to be decreased. * @return The #LinphonePresenceNote object if the reference count is still positive, NULL if the object has been destroyed. */ -LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note); +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note); /** * Sets the user data of a #LinphonePresenceNote object. * @param[in] note The #LinphonePresenceNote object for which to set the user data. * @param[in] user_data A pointer to the user data to set. */ -void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data); +LINPHONE_PUBLIC void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data); /** * Gets the user data of a #LinphonePresenceNote object. * @param[in] note The #LinphonePresenceNote object for which to get the user data. * @return A pointer to the user data. */ -void * linphone_presence_note_get_user_data(LinphonePresenceNote *note); +LINPHONE_PUBLIC void * linphone_presence_note_get_user_data(LinphonePresenceNote *note); /***************************************************************************** diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index f413bf7a6..3af570e79 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -167,7 +167,7 @@ LINPHONE_PUBLIC void lp_config_set_int(LpConfig *lpconfig,const char *section, c * * @ingroup misc **/ -void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value); +LINPHONE_PUBLIC void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value); /** * Sets a 64 bits integer config item @@ -220,7 +220,7 @@ void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, voi /*tells whether uncommited (with lp_config_sync()) modifications exist*/ int lp_config_needs_commit(const LpConfig *lpconfig); -void lp_config_destroy(LpConfig *cfg); +LINPHONE_PUBLIC void lp_config_destroy(LpConfig *cfg); #ifdef __cplusplus } From 6aba836d5cd618d6b4dd4206bcfd6d97ba40d205 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 20 Dec 2013 16:30:28 +0100 Subject: [PATCH 076/439] Update ms2 submodule for missing symbol exports. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 1451d9c76..4103f0b1d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1451d9c76af5741f89d21bc96ab40032647ffa7a +Subproject commit 4103f0b1d7757558d06e6e32b657308bb2556c9b From 62eaa0c0e551c1b42c4c642e926e5429afd03e33 Mon Sep 17 00:00:00 2001 From: margaux clerc Date: Sat, 7 Dec 2013 12:38:43 +0100 Subject: [PATCH 077/439] Add wizard button in preferences only if it is enabled Changes the version of .ui for older gtk version Fix chat without message storage --- configure.ac | 2 +- gtk/call_statistics.ui | 2 +- gtk/chat.c | 14 ++++++++++---- gtk/keypad.ui | 2 +- gtk/main.c | 2 +- gtk/propertybox.c | 3 +++ 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index a35089e36..d44cda018 100644 --- a/configure.ac +++ b/configure.ac @@ -710,7 +710,7 @@ AC_ARG_ENABLE(msg-storage, AM_CONDITIONAL(BUILD_MSG_STORAGE, test x$enable_msg_storage = xtrue) if test x$enable_msg_storage != xfalse; then - PKG_CHECK_MODULES(SQLITE3,[ sqlite3 >= 3.7.0],[ + PKG_CHECK_MODULES(SQLITE3,[ sqlite3 >= 3.6.0],[ SQLITE3_CFLAGS+="-DMSG_STORAGE_ENABLED" AC_SUBST(SQLITE3_CFLAGS) AC_SUBST(SQLITE3_LIBS) diff --git a/gtk/call_statistics.ui b/gtk/call_statistics.ui index c6f71deb6..a647a8dca 100644 --- a/gtk/call_statistics.ui +++ b/gtk/call_statistics.ui @@ -1,6 +1,6 @@ - + False diff --git a/gtk/chat.c b/gtk/chat.c index bfb6529e8..b44605ae3 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -357,7 +357,7 @@ void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with){ GtkWidget *chat_view=linphone_gtk_create_widget("main","chatroom_frame"); - GtkWidget *main_window=linphone_gtk_get_main_window (); + GtkWidget *main_window=linphone_gtk_get_main_window(); GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); GtkWidget *text=linphone_gtk_get_widget(chat_view,"textview"); GdkColor color; @@ -375,7 +375,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres colorb.red = 56832; colorb.green = 60928; colorb.blue = 61952; - + with_str=linphone_address_as_string_uri_only(with); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text),GTK_WRAP_WORD_CHAR); gtk_text_view_set_editable(GTK_TEXT_VIEW(text),FALSE); @@ -468,9 +468,10 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, gboolean send=TRUE; /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ const LinphoneAddress *from= linphone_chat_message_get_from ( msg ); - + w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); if ( w!=NULL ) { + /* Chat window opened */ const LinphoneAddress *from_chatview=linphone_gtk_friend_list_get_active_address(); if (linphone_address_weak_equal(from,from_chatview)) { send=TRUE; @@ -480,8 +481,13 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, } send=FALSE; } - } else { + } else { + /* Chat window closed */ +#ifdef MSG_STORAGE_ENABLED send=FALSE; +#else + send=TRUE; +#endif if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) { linphone_gtk_chat_add_contact ( linphone_chat_message_get_from ( msg ) ); } diff --git a/gtk/keypad.ui b/gtk/keypad.ui index 5dfcfc487..2dd62a0f0 100644 --- a/gtk/keypad.ui +++ b/gtk/keypad.ui @@ -1,6 +1,6 @@ - + False diff --git a/gtk/main.c b/gtk/main.c index a25b42523..135dfe5f4 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1591,7 +1591,7 @@ static void linphone_gtk_init_status_icon(){ const char *title; title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone")); icon=gtk_status_icon_new_from_pixbuf(pbuf); -#if GTK_CHECK_VERSION(2,20,0) +#if GTK_CHECK_VERSION(2,20,2) gtk_status_icon_set_name(icon,title); #endif g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 57f3b0c4e..46a750ead 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1400,6 +1400,9 @@ void linphone_gtk_show_parameters(void){ if (linphone_address_get_username(contact)) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"username")),linphone_address_get_username(contact)); } +#ifdef BUILD_WIZARD + gtk_widget_show(linphone_gtk_get_widget(pb,"wizard")); +#endif linphone_address_destroy(contact); linphone_gtk_show_sip_accounts(pb); /* CODECS CONFIG */ From b0d827bae5b590a2da8d6d7e2b718a687372cb30 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 23 Dec 2013 12:14:18 +0100 Subject: [PATCH 078/439] Updated wp8 build project --- 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 25e1543e4..c2d421126 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -234,6 +234,9 @@ {072fad20-7007-4da2-b2e7-16ce2b219f67} + + {b16b81a9-bef2-44c9-b603-1065183ae844} + {36b528f9-fb79-4078-a16b-0a7442581bb7} From 68ff65b224ae85970d9d335f6b8d604687843c22 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 24 Dec 2013 10:59:08 +0100 Subject: [PATCH 079/439] turn ping_with_options to 0 by default, since it is no longer required thanks to belle-sip --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 104925d51..f4773e111 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -710,7 +710,7 @@ static void sip_config_read(LinphoneCore *lc) lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); lc->sip_conf.register_only_when_upnp_is_ok= lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1); - lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1); + lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",0); lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1); lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000); lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); From d652965ce4b7d23d49516ea642a6ad51af8c0c1b Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Sun, 22 Dec 2013 21:37:09 +0100 Subject: [PATCH 080/439] Add wizard button in preferences only if it is enabled Changes the version of .ui for older gtk version Fix chat without message storage --- configure.ac | 2 +- gtk/call_statistics.ui | 2 +- gtk/chat.c | 14 ++++++++++---- gtk/keypad.ui | 2 +- gtk/main.c | 2 +- gtk/propertybox.c | 3 +++ 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index a35089e36..d44cda018 100644 --- a/configure.ac +++ b/configure.ac @@ -710,7 +710,7 @@ AC_ARG_ENABLE(msg-storage, AM_CONDITIONAL(BUILD_MSG_STORAGE, test x$enable_msg_storage = xtrue) if test x$enable_msg_storage != xfalse; then - PKG_CHECK_MODULES(SQLITE3,[ sqlite3 >= 3.7.0],[ + PKG_CHECK_MODULES(SQLITE3,[ sqlite3 >= 3.6.0],[ SQLITE3_CFLAGS+="-DMSG_STORAGE_ENABLED" AC_SUBST(SQLITE3_CFLAGS) AC_SUBST(SQLITE3_LIBS) diff --git a/gtk/call_statistics.ui b/gtk/call_statistics.ui index c6f71deb6..a647a8dca 100644 --- a/gtk/call_statistics.ui +++ b/gtk/call_statistics.ui @@ -1,6 +1,6 @@ - + False diff --git a/gtk/chat.c b/gtk/chat.c index bfb6529e8..b44605ae3 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -357,7 +357,7 @@ void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with){ GtkWidget *chat_view=linphone_gtk_create_widget("main","chatroom_frame"); - GtkWidget *main_window=linphone_gtk_get_main_window (); + GtkWidget *main_window=linphone_gtk_get_main_window(); GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch"); GtkWidget *text=linphone_gtk_get_widget(chat_view,"textview"); GdkColor color; @@ -375,7 +375,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres colorb.red = 56832; colorb.green = 60928; colorb.blue = 61952; - + with_str=linphone_address_as_string_uri_only(with); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text),GTK_WRAP_WORD_CHAR); gtk_text_view_set_editable(GTK_TEXT_VIEW(text),FALSE); @@ -468,9 +468,10 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, gboolean send=TRUE; /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ const LinphoneAddress *from= linphone_chat_message_get_from ( msg ); - + w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); if ( w!=NULL ) { + /* Chat window opened */ const LinphoneAddress *from_chatview=linphone_gtk_friend_list_get_active_address(); if (linphone_address_weak_equal(from,from_chatview)) { send=TRUE; @@ -480,8 +481,13 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, } send=FALSE; } - } else { + } else { + /* Chat window closed */ +#ifdef MSG_STORAGE_ENABLED send=FALSE; +#else + send=TRUE; +#endif if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) { linphone_gtk_chat_add_contact ( linphone_chat_message_get_from ( msg ) ); } diff --git a/gtk/keypad.ui b/gtk/keypad.ui index 5dfcfc487..2dd62a0f0 100644 --- a/gtk/keypad.ui +++ b/gtk/keypad.ui @@ -1,6 +1,6 @@ - + False diff --git a/gtk/main.c b/gtk/main.c index a25b42523..135dfe5f4 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1591,7 +1591,7 @@ static void linphone_gtk_init_status_icon(){ const char *title; title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone")); icon=gtk_status_icon_new_from_pixbuf(pbuf); -#if GTK_CHECK_VERSION(2,20,0) +#if GTK_CHECK_VERSION(2,20,2) gtk_status_icon_set_name(icon,title); #endif g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL); diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 57f3b0c4e..46a750ead 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1400,6 +1400,9 @@ void linphone_gtk_show_parameters(void){ if (linphone_address_get_username(contact)) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"username")),linphone_address_get_username(contact)); } +#ifdef BUILD_WIZARD + gtk_widget_show(linphone_gtk_get_widget(pb,"wizard")); +#endif linphone_address_destroy(contact); linphone_gtk_show_sip_accounts(pb); /* CODECS CONFIG */ From fe1ca6f07c5735d08e80ff08008378384ac239dc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 3 Jan 2014 12:36:54 +0100 Subject: [PATCH 081/439] update READMEs for mingw and macos --- README.macos | 2 +- README.mingw | 103 ++++++++++++++++++++++----------------------------- 2 files changed, 45 insertions(+), 60 deletions(-) diff --git a/README.macos b/README.macos index db01b4869..cc89ded86 100644 --- a/README.macos +++ b/README.macos @@ -30,7 +30,7 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ export CFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export OBJCFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" - $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" + $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5 -Wl,-headerpad_max_install_names" - Install libantlr3c (library used by belle-sip for parsing) $ git clone -b linphone git://git.linphone.org/antlr3.git diff --git a/README.mingw b/README.mingw index cb1f60c01..4ac4661a7 100644 --- a/README.mingw +++ b/README.mingw @@ -9,7 +9,7 @@ In the feature list, select: * Mingw developer toolkit Let the installer fetch and install everything. -In mingw shell, run +In mingw shell (also refered as msys), run mingw-get install msys-zip mingw-get install msys-unzip @@ -45,70 +45,63 @@ libintl.a libintl.la libintl.dll.a * Download and install Inno Setup Compiler (required only if you run 'make setup.exe'). Add it to your windows Path environment variable. -Get Linphone source code -************************ +* Install msys-git from (http://code.google.com/p/msysgit/). During installation you are asked to make a choice about how line endings are treated by git. Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE. -Install msys-git from (http://code.google.com/p/msysgit/). During installation you are asked to make a choice about how line endings are treated by git. -Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE. -It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example -c:\sources\ -Within msys-git bash, do +General rules for compilation +***************************** + +- It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example c:\sources\. + This is the place where source code must be compiled. +- git commands (to retrieve source code) must be performed within msys-git terminal. +- all other commands (configure, autogen.sh, make) must be done within the mingw shell (msys). +In both msys and msys-git windows, change into the directory you created for sources: cd /c/sources -git clone git://git.linphone.org/linphone.git --recursive +Building belle-sip +****************** + * download the sources with msys-git shell using the following command: + $ git clone git://git.linphone.org/belle-sip.git + * compile and install + $ ./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + $ make && make install -Building -******** +Building Linphone +***************** -WARNING: During the build, windows might slow down suddenly. Using ctl+alt+del to start the windows system monitor, - you might see a process 'LVpSRV.exe' or something like this that eats 90% of cpu. -Kill it. Don't know what it is, but once killed, windows runs normally. + * download the sources using the following command: + $ git clone git://git.linphone.org/linphone.git --recursive -#Build linphone itself: -#run autogen.sh after a git checkout or update + * compile + #always run autogen.sh after a git checkout or update + $ ./autogen.sh -./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + #note: in order to use the tunnel (commercial extension), append --enable-tunnel to the configure line above. -./configure --prefix=/usr --enable-shared --disable-static -#note: in order to use the tunnel, append --enable-tunnel to the configure line above. + $ make + $ make install -#compile: + #Option: make a portable binary zip of linphone + $ make zip -make + #additionally you can make binary installer if you have Inno Setup 5 installed in its default path -#now install to /usr, required for compilation of plugins. + $ make setup.exe + #now you're done, you have a fresh linphone windows installer in the current directory. -make install +Building plugins (optional) +*************************** -#make a binary zip of linphone - -make zip - -#additionally you can make binary installer if you have Inno Setup 5 installed in its default path - -make setup.exe - -#now you're done, you have a fresh linphone windows installer in the current directory. - - - -#build plugins -cd mediastreamer2/plugins/msx264 -./autogen.sh -PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static -#make a binary zip of this plugin -make zip -#or make an installer -make setup.exe - -#the buddylookup plugin enables lookup of buddies in a remote database using xml-rpc over http/https. -cd coreapi/plugins/buddylookup -./autogen.sh -PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static -make -#make a binary zip of this plugin -make zip + This the example for msx264 (H264 plugin), the same applies for other linphone plugins. + $ cd mediastreamer2/plugins/msx264 + $ ./autogen.sh + $ PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static + #make a binary zip of this plugin + $ make zip + #or make an installer + $ make setup.exe ****************************************************** @@ -161,14 +154,6 @@ When running "make install DESTDIR=", somepath must be absolute and sh $ 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 From d468050c8ba5daec52477df6229c77773a831478 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 2 Jan 2014 15:41:40 +0100 Subject: [PATCH 082/439] Implement RFC3994: Indication of Message Composition for Instant Messaging. --- console/Makefile.am | 6 +- coreapi/Makefile.am | 1 + coreapi/bellesip_sal/sal_impl.c | 11 +- coreapi/bellesip_sal/sal_op_message.c | 20 ++- coreapi/callbacks.c | 16 +- coreapi/chat.c | 246 +++++++++++++++++++++++++- coreapi/linphonecore.h | 23 +++ coreapi/presence.c | 173 +++++------------- coreapi/private.h | 40 +++++ coreapi/xml.c | 98 ++++++++++ gtk/chat.c | 21 ++- gtk/friendlist.c | 24 ++- gtk/linphone.h | 1 + gtk/main.c | 1 + include/sal/sal.h | 10 ++ pixmaps/Makefile.am | 2 +- pixmaps/active_chat.png | Bin 3415 -> 3386 bytes pixmaps/composing_active_chat.png | Bin 0 -> 3398 bytes pixmaps/composing_chat.png | Bin 0 -> 3291 bytes tester/Makefile.am | 4 +- 20 files changed, 552 insertions(+), 145 deletions(-) create mode 100644 coreapi/xml.c create mode 100644 pixmaps/composing_active_chat.png create mode 100644 pixmaps/composing_chat.png diff --git a/console/Makefile.am b/console/Makefile.am index 3a975e9c4..314f5d612 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -13,7 +13,8 @@ COMMON_CFLAGS=\ $(MEDIASTREAMER_CFLAGS) \ $(VIDEO_CFLAGS) \ $(READLINE_CFLAGS) \ - $(SQLITE3_CFLAGS) + $(SQLITE3_CFLAGS) \ + $(LIBXML2_CFLAGS) if BUILD_CONSOLE @@ -29,7 +30,8 @@ linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la \ $(READLINE_LIBS) \ $(SQLITE3_LIBS) \ $(X11_LIBS) \ - $(BELLESIP_LIBS) + $(BELLESIP_LIBS) \ + $(LIBXML2_LIBS) if BUILD_WIN32 #special build of linphonec to detach from the windows console diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 3933ddb05..61d240464 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -51,6 +51,7 @@ liblinphone_la_SOURCES=\ contactprovider.c contactprovider.h contact_providers_priv.h \ ldap/ldapprovider.c ldap/ldapprovider.h \ dict.c \ + xml.c \ $(GITVERSION_FILE) if BUILD_UPNP diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 08986eb89..f15b07ffb 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -464,6 +464,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub; if (ctx->callbacks.text_received==NULL) ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; + if (ctx->callbacks.is_composing_received==NULL) + ctx->callbacks.is_composing_received=(SalOnIsComposingReceived)unimplemented_stub; if (ctx->callbacks.ping_reply==NULL) ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; if (ctx->callbacks.auth_requested==NULL) @@ -915,5 +917,12 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ return belle_sip_random_bytes(ret,size); } +belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) { + belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); + return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name); +} - +void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) { + belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); + belle_sip_main_loop_remove_source(ml, timer); +} diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 1e3dc12f0..25402aef2 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -76,6 +76,10 @@ static bool_t is_external_body(belle_sip_header_content_type_t* content_type) { return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0 && strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0; } +static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) { + return strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("im-iscomposing+xml",belle_sip_header_content_type_get_subtype(content_type))==0; +} static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; @@ -88,8 +92,6 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t); - SalMessage salmsg; - char message_id[256]={0}; int response_code=501; char* from; bool_t plain_text=FALSE; @@ -99,7 +101,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); if (content_type && ((plain_text=is_plain_text(content_type)) || (external_body=is_external_body(content_type)))) { - + SalMessage salmsg; + char message_id[256]={0}; 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)); @@ -121,6 +124,17 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_free(from); if (salmsg.url) ms_free((char*)salmsg.url); response_code=200; + } else if (content_type && is_im_iscomposing(content_type)) { + SalIsComposing saliscomposing; + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); + saliscomposing.from=from; + saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + op->base.root->callbacks.is_composing_received(op,&saliscomposing); + 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)); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a9c364c52..3ebce7488 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -843,6 +843,11 @@ static void text_received(SalOp *op, const SalMessage *msg){ } } +static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) { + LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + linphone_core_is_composing_received(lc, op, is_composing); +} + 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); } @@ -1001,8 +1006,14 @@ static int op_equals(LinphoneCall *a, SalOp *b) { 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); - + const MSList* calls; + + if (chat_msg == NULL) { + // Do not handle delivery status for isComposing messages. + return; + } + calls = linphone_core_get_calls(chat_msg->chat_room->lc); + chat_msg->state=chatStatusSal2Linphone(status); linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { @@ -1123,6 +1134,7 @@ SalCallbacks linphone_sal_callbacks={ refer_received, text_received, text_delivery_update, + is_composing_received, notify_refer, subscribe_received, subscribe_closed, diff --git a/coreapi/chat.c b/coreapi/chat.c index c2e6a9cf5..ddb6ba262 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -26,6 +26,12 @@ #include "private.h" #include "lpconfig.h" +#include + +#define COMPOSING_DEFAULT_IDLE_TIMEOUT 15 +#define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 +#define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120 + /** * @addtogroup chatroom * @{ @@ -85,13 +91,40 @@ LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const } return ret; } - + +static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) { + if (cr->composing_idle_timer) { + sal_cancel_timer(cr->lc->sal, cr->composing_idle_timer); + belle_sip_object_unref(cr->composing_idle_timer); + cr->composing_idle_timer = NULL; + } +} + +static void linphone_chat_room_delete_composing_refresh_timer(LinphoneChatRoom *cr) { + if (cr->composing_refresh_timer) { + sal_cancel_timer(cr->lc->sal, cr->composing_refresh_timer); + belle_sip_object_unref(cr->composing_refresh_timer); + cr->composing_refresh_timer = NULL; + } +} + +static void linphone_chat_room_delete_remote_composing_refresh_timer(LinphoneChatRoom *cr) { + if (cr->remote_composing_refresh_timer) { + sal_cancel_timer(cr->lc->sal, cr->remote_composing_refresh_timer); + belle_sip_object_unref(cr->remote_composing_refresh_timer); + cr->remote_composing_refresh_timer = NULL; + } +} + /** * Destroy a LinphoneChatRoom. * @param cr #LinphoneChatRoom object */ void linphone_chat_room_destroy(LinphoneChatRoom *cr){ LinphoneCore *lc=cr->lc; + linphone_chat_room_delete_composing_idle_timer(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); + linphone_chat_room_delete_remote_composing_refresh_timer(cr); lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr); linphone_address_destroy(cr->peer_url); ms_free(cr->peer); @@ -142,6 +175,12 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM msg->dir=LinphoneChatMessageOutgoing; msg->from=linphone_address_new(identity); msg->storage_id=linphone_chat_message_store(msg); + + if (cr->is_composing == LinphoneIsComposingActive) { + cr->is_composing = LinphoneIsComposingIdle; + } + linphone_chat_room_delete_composing_idle_timer(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); } /** @@ -225,6 +264,89 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag ms_free(from); } +static int linphone_chat_room_remote_refresh_composing_expired(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + belle_sip_object_unref(cr->remote_composing_refresh_timer); + cr->remote_composing_refresh_timer = NULL; + cr->remote_is_composing = LinphoneIsComposingIdle; + if (cr->lc->vtable.is_composing_received != NULL) + cr->lc->vtable.is_composing_received(cr->lc, cr); + return BELLE_SIP_STOP; +} + +static const char *iscomposing_prefix = "/xsi:isComposing"; + +static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsing_context_t *xml_ctx) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr iscomposing_object; + const char *state_str = NULL; + const char *refresh_str = NULL; + int refresh_duration = COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT; + int i; + LinphoneIsComposingState state = LinphoneIsComposingIdle; + + if (linphone_create_xml_xpath_context(xml_ctx) < 0) return; + + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"xsi", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing"); + iscomposing_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, iscomposing_prefix); + if ((iscomposing_object != NULL) && (iscomposing_object->nodesetval != NULL)) { + for (i = 1; i <= iscomposing_object->nodesetval->nodeNr; i++) { + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:state", iscomposing_prefix, i); + state_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + if (state_str == NULL) continue; + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:refresh", iscomposing_prefix, i); + refresh_str = linphone_get_xml_text_content(xml_ctx, xpath_str); + } + } + + if (state_str != NULL) { + if (strcmp(state_str, "active") == 0) { + state = LinphoneIsComposingActive; + if (refresh_str != NULL) { + refresh_duration = atoi(refresh_str); + } + if (!cr->remote_composing_refresh_timer) { + cr->remote_composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_remote_refresh_composing_expired, cr, refresh_duration * 1000, "composing remote refresh timeout"); + } else { + belle_sip_source_set_timeout(cr->remote_composing_refresh_timer, refresh_duration * 1000); + } + } else { + linphone_chat_room_delete_remote_composing_refresh_timer(cr); + } + + cr->remote_is_composing = state; + if (cr->lc->vtable.is_composing_received != NULL) + cr->lc->vtable.is_composing_received(cr->lc, cr); + } +} + +static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const char *text) { + xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error); + xml_ctx->doc = xmlReadDoc((const unsigned char*)text, 0, NULL, 0); + if (xml_ctx->doc != NULL) { + process_im_is_composing_notification(cr, xml_ctx); + } else { + ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer); + } + linphone_xmlparsing_context_destroy(xml_ctx); +} + +void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) { + LinphoneChatRoom *cr = NULL; + LinphoneAddress *addr = linphone_address_new(is_composing->from); + linphone_address_clean(addr); + cr = linphone_core_get_chat_room(lc, addr); + if (cr != NULL) { + linphone_chat_room_notify_is_composing(cr, is_composing->text); + } + linphone_address_destroy(addr); +} + +bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { + return (cr->remote_is_composing == LinphoneIsComposingActive) ? TRUE : FALSE; +} + /** * Returns back pointer to LinphoneCore object. **/ @@ -319,6 +441,128 @@ void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* _linphone_chat_room_send_message(cr, msg); } +static char * linphone_chat_room_create_is_composing_xml(LinphoneChatRoom *cr) { + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + char *content = NULL; + + buf = xmlBufferCreate(); + if (buf == NULL) { + ms_error("Error creating the XML buffer"); + return content; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + ms_error("Error creating the XML writer"); + return content; + } + + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"isComposing", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"xsi", + NULL, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xsi", (const xmlChar *)"schemaLocation", + NULL, (const xmlChar *)"urn:ietf:params:xml:ns:im-composing iscomposing.xsd"); + } + if (err >= 0) { + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"state", + (cr->is_composing == LinphoneIsComposingActive) ? (const xmlChar *)"active" : (const xmlChar *)"idle"); + } + if ((err >= 0) && (cr->is_composing == LinphoneIsComposingActive)) { + char refresh_str[4] = { 0 }; + snprintf(refresh_str, sizeof(refresh_str), "%u", COMPOSING_DEFAULT_REFRESH_TIMEOUT); + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"refresh", (const xmlChar *)refresh_str); + } + if (err >= 0) { + /* Close the "isComposing" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + if (err > 0) { + /* xmlTextWriterEndDocument returns the size of the content. */ + content = ms_strdup((char *)buf->content); + } + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + return content; +} + +static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom *cr) { + SalOp *op = NULL; + LinphoneCall *call; + const char *identity = NULL; + char *content = NULL; + + if (lp_config_get_int(cr->lc->config, "sip", "chat_use_call_dialogs", 0)) { + if ((call = linphone_core_get_call_by_remote_address(cr->lc, cr->peer)) != NULL) { + if (call->state == LinphoneCallConnected || + call->state == LinphoneCallStreamsRunning || + call->state == LinphoneCallPaused || + call->state == LinphoneCallPausing || + call->state == LinphoneCallPausedByRemote) { + ms_message("send SIP message through the existing call."); + op = call->op; + identity = linphone_core_find_best_identity(cr->lc, linphone_call_get_remote_address(call)); + } + } + } + if (op == NULL) { + LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url); + if (proxy) + identity = linphone_proxy_config_get_identity(proxy); + else + identity = linphone_core_get_primary_contact(cr->lc); + /*sending out of calls*/ + op = sal_op_new(cr->lc->sal); + linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0)); + } + content = linphone_chat_room_create_is_composing_xml(cr); + if (content != NULL) { + sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content); + ms_free(content); + } +} + +static int linphone_chat_room_stop_composing(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + cr->is_composing = LinphoneIsComposingIdle; + linphone_chat_room_send_is_composing_notification(cr); + linphone_chat_room_delete_composing_refresh_timer(cr); + belle_sip_object_unref(cr->composing_idle_timer); + cr->composing_idle_timer = NULL; + return BELLE_SIP_STOP; +} + +static int linphone_chat_room_refresh_composing(void *data, unsigned int revents) { + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + linphone_chat_room_send_is_composing_notification(cr); + return BELLE_SIP_CONTINUE; +} + +void linphone_chat_room_compose(LinphoneChatRoom *cr) { + if (cr->is_composing == LinphoneIsComposingIdle) { + cr->is_composing = LinphoneIsComposingActive; + linphone_chat_room_send_is_composing_notification(cr); + if (!cr->composing_refresh_timer) { + cr->composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_refresh_composing, cr, COMPOSING_DEFAULT_REFRESH_TIMEOUT * 1000, "composing refresh timeout"); + } else { + belle_sip_source_set_timeout(cr->composing_refresh_timer, COMPOSING_DEFAULT_REFRESH_TIMEOUT * 1000); + } + if (!cr->composing_idle_timer) { + cr->composing_idle_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_stop_composing, cr, COMPOSING_DEFAULT_IDLE_TIMEOUT * 1000, "composing idle timeout"); + } + } + belle_sip_source_set_timeout(cr->composing_idle_timer, COMPOSING_DEFAULT_IDLE_TIMEOUT * 1000); +} + /** * Returns a #LinphoneChatMessageState as a string. */ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c6a3332df..4aa4d0942 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -977,6 +977,20 @@ LINPHONE_PUBLIC MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg); LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr); + +/** + * Notify the destination of the chat message being composed that the user is typing a new message. + * @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which a new message is being typed. + */ +LINPHONE_PUBLIC void linphone_chat_room_compose(LinphoneChatRoom *cr); + +/** + * Tells whether the remote is currently composing a message. + * @param[in] cr The "LinphoneChatRoom object corresponding to the conversation. + * @return TRUE if the remote is currently composing a message, FALSE otherwise. + */ +LINPHONE_PUBLIC bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr); + LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); @@ -1130,6 +1144,14 @@ typedef void (*LinphoneCoreTextMessageReceivedCb)(LinphoneCore *lc, LinphoneChat */ typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); +/** + * Is composing notification callback prototype. + * + * @param[in] lc #LinphoneCore object + * @param[in] room #LinphoneChatRoom involved in the conversation. + */ +typedef void (*LinphoneCoreIsComposingReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room); + /** * Callback for being notified of DTMFs received. * @param lc the linphone core @@ -1179,6 +1201,7 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreAuthInfoRequestedCb auth_info_requested; /**< Ask the application some authentication information */ LinphoneCoreCallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */ LinphoneCoreMessageReceivedCb message_received; /** a message is received, can be text or external body*/ + LinphoneCoreIsComposingReceivedCb is_composing_received; /**< An is-composing notification has been received */ LinphoneCoreDtmfReceivedCb dtmf_received; /**< A dtmf has been received received */ LinphoneCoreReferReceivedCb refer_received; /**< An out of call refer was received */ LinphoneCoreCallEncryptionChangedCb call_encryption_changed; /** -#include -#include -#include - - -#define XMLPARSING_BUFFER_LEN 2048 -#define MAX_XPATH_LENGTH 256 - extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); @@ -83,13 +74,6 @@ struct _LinphonePresenceModel { MSList *notes; /**< A list of _LinphonePresenceNote structures. */ }; -typedef struct _xmlparsing_context { - xmlDoc *doc; - xmlXPathContextPtr xpath_ctx; - char errorBuffer[XMLPARSING_BUFFER_LEN]; - char warningBuffer[XMLPARSING_BUFFER_LEN]; -} xmlparsing_context_t; - static const char *person_prefix = "/pidf:presence/dm:person"; @@ -98,38 +82,6 @@ static const char *person_prefix = "/pidf:presence/dm:person"; * PRIVATE FUNCTIONS * ****************************************************************************/ -static xmlparsing_context_t * xmlparsing_context_new() { - xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t)); - if (xmlCtx != NULL) { - xmlCtx->doc = NULL; - xmlCtx->xpath_ctx = NULL; - xmlCtx->errorBuffer[0] = '\0'; - xmlCtx->warningBuffer[0] = '\0'; - } - return xmlCtx; -} - -static void xmlparsing_context_destroy(xmlparsing_context_t *ctx) { - if (ctx->doc != NULL) { - xmlFreeDoc(ctx->doc); - ctx->doc = NULL; - } - if (ctx->xpath_ctx != NULL) { - xmlXPathFreeContext(ctx->xpath_ctx); - ctx->xpath_ctx = NULL; - } - free(ctx); -} - -static void xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) { - xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx; - int sl = strlen(xmlCtx->errorBuffer); - va_list args; - va_start(args, fmt); - vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args); - va_end(args); -} - static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz"; static char * generate_presence_id(void) { @@ -1183,45 +1135,6 @@ void * linphone_presence_note_get_user_data(LinphonePresenceNote *note) { * XML PRESENCE INTERNAL HANDLING * ****************************************************************************/ -static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { - if (xml_ctx->xpath_ctx != NULL) { - xmlXPathFreeContext(xml_ctx->xpath_ctx); - } - xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc); - if (xml_ctx->xpath_ctx == NULL) return -1; - return 0; -} - -static char * get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { - xmlXPathObjectPtr xpath_obj; - xmlChar *text = NULL; - int i; - - xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); - if (xpath_obj != NULL) { - if (xpath_obj->nodesetval != NULL) { - xmlNodeSetPtr nodes = xpath_obj->nodesetval; - for (i = 0; i < nodes->nodeNr; i++) { - xmlNodePtr node = nodes->nodeTab[i]; - if (node->children != NULL) { - text = xmlNodeListGetString(xml_ctx->doc, node->children, 1); - } - } - } - xmlXPathFreeObject(xpath_obj); - } - - return (char *)text; -} - -static void free_xml_text_content(const char *text) { - xmlFree((xmlChar *)text); -} - -static xmlXPathObjectPtr get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { - return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); -} - static const char *service_prefix = "/pidf:presence/pidf:tuple"; static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx, LinphonePresenceService *service, unsigned int service_idx) { @@ -1233,19 +1146,19 @@ static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx int i; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note", service_prefix, service_idx); - note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]", service_prefix, service_idx, i); - note_str = get_xml_text_content(xml_ctx, xpath_str); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]/@xml:lang", service_prefix, service_idx, i); - lang = get_xml_text_content(xml_ctx, xpath_str); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); note = linphone_presence_note_new(note_str, lang); presence_service_add_note(service, note); - if (lang != NULL) free_xml_text_content(lang); - free_xml_text_content(note_str); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); } } if (note_object != NULL) xmlXPathFreeObject(note_object); @@ -1264,11 +1177,11 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin LinphonePresenceBasicStatus basic_status; int i; - service_object = get_xml_xpath_object_for_node_list(xml_ctx, service_prefix); + service_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, service_prefix); if ((service_object != NULL) && (service_object->nodesetval != NULL)) { for (i = 1; i <= service_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:status/pidf:basic", service_prefix, i); - basic_status_str = get_xml_text_content(xml_ctx, xpath_str); + basic_status_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (basic_status_str == NULL) continue; @@ -1278,33 +1191,33 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin basic_status = LinphonePresenceBasicStatusClosed; } else { /* Invalid value for basic status. */ - free_xml_text_content(basic_status_str); + linphone_free_xml_text_content(basic_status_str); return -1; } snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", service_prefix, i); - timestamp_str = get_xml_text_content(xml_ctx, xpath_str); + timestamp_str = linphone_get_xml_text_content(xml_ctx, xpath_str); snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:contact", service_prefix, i); - contact_str = get_xml_text_content(xml_ctx, xpath_str); + contact_str = linphone_get_xml_text_content(xml_ctx, xpath_str); snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", service_prefix, i); - service_id_str = get_xml_text_content(xml_ctx, xpath_str); + service_id_str = linphone_get_xml_text_content(xml_ctx, xpath_str); service = presence_service_new(service_id_str, basic_status); if (service != NULL) { if (timestamp_str != NULL) { presence_service_set_timestamp(service, parse_timestamp(timestamp_str)); - free_xml_text_content(timestamp_str); + linphone_free_xml_text_content(timestamp_str); } if (contact_str != NULL) { linphone_presence_service_set_contact(service, contact_str); - free_xml_text_content(contact_str); + linphone_free_xml_text_content(contact_str); } process_pidf_xml_presence_service_notes(xml_ctx, service, i); linphone_presence_model_add_service(model, service); } - free_xml_text_content(basic_status_str); - if (service_id_str != NULL) free_xml_text_content(service_id_str); + linphone_free_xml_text_content(basic_status_str); + if (service_id_str != NULL) linphone_free_xml_text_content(service_id_str); } } if (service_object != NULL) xmlXPathFreeObject(service_object); @@ -1333,11 +1246,11 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml int err = 0; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities", person_prefix, person_idx); - activities_nodes_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + activities_nodes_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((activities_nodes_object != NULL) && (activities_nodes_object->nodesetval != NULL)) { for (i = 1; i <= activities_nodes_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities[%i]/rpid:*", person_prefix, person_idx, i); - activities_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + activities_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((activities_object != NULL) && (activities_object->nodesetval != NULL)) { for (j = 0; j < activities_object->nodesetval->nodeNr; j++) { activity_node = activities_object->nodesetval->nodeTab[j]; @@ -1345,14 +1258,14 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml LinphonePresenceActivityType acttype; description = (const char *)xmlNodeGetContent(activity_node); if ((description != NULL) && (description[0] == '\0')) { - free_xml_text_content(description); + linphone_free_xml_text_content(description); description = NULL; } err = activity_name_to_presence_activity_type((const char *)activity_node->name, &acttype); if (err < 0) break; activity = linphone_presence_activity_new(acttype, description); linphone_presence_person_add_activity(person, activity); - if (description != NULL) free_xml_text_content(description); + if (description != NULL) linphone_free_xml_text_content(description); } } } @@ -1374,37 +1287,37 @@ static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, int i; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note", person_prefix, person_idx); - note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]", person_prefix, person_idx, i); - note_str = get_xml_text_content(xml_ctx, xpath_str); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i); - lang = get_xml_text_content(xml_ctx, xpath_str); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); note = linphone_presence_note_new(note_str, lang); presence_person_add_activities_note(person, note); - if (lang != NULL) free_xml_text_content(lang); - free_xml_text_content(note_str); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); } } if (note_object != NULL) xmlXPathFreeObject(note_object); snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note", person_prefix, person_idx); - note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]", person_prefix, person_idx, i); - note_str = get_xml_text_content(xml_ctx, xpath_str); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]/@xml:lang", person_prefix, person_idx, i); - lang = get_xml_text_content(xml_ctx, xpath_str); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); note = linphone_presence_note_new(note_str, lang); presence_person_add_note(person, note); - if (lang != NULL) free_xml_text_content(lang); - free_xml_text_content(note_str); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); } } if (note_object != NULL) xmlXPathFreeObject(note_object); @@ -1422,13 +1335,13 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp int i; int err = 0; - person_object = get_xml_xpath_object_for_node_list(xml_ctx, person_prefix); + person_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, person_prefix); if ((person_object != NULL) && (person_object->nodesetval != NULL)) { for (i = 1; i <= person_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", person_prefix, i); - person_id_str = get_xml_text_content(xml_ctx, xpath_str); + person_id_str = linphone_get_xml_text_content(xml_ctx, xpath_str); snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", person_prefix, i); - person_timestamp_str = get_xml_text_content(xml_ctx, xpath_str); + person_timestamp_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (person_timestamp_str == NULL) timestamp = time(NULL); else @@ -1446,8 +1359,8 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp break; } } - if (person_id_str != NULL) free_xml_text_content(person_id_str); - if (person_timestamp_str != NULL) free_xml_text_content(person_timestamp_str); + if (person_id_str != NULL) linphone_free_xml_text_content(person_id_str); + if (person_timestamp_str != NULL) linphone_free_xml_text_content(person_timestamp_str); } } if (person_object != NULL) xmlXPathFreeObject(person_object); @@ -1467,19 +1380,19 @@ static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, Linpho const char *lang; int i; - note_object = get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note"); + note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note"); if ((note_object != NULL) && (note_object->nodesetval != NULL)) { for (i = 1; i <= note_object->nodesetval->nodeNr; i++) { snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]", i); - note_str = get_xml_text_content(xml_ctx, xpath_str); + note_str = linphone_get_xml_text_content(xml_ctx, xpath_str); if (note_str == NULL) continue; snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]/@xml:lang", i); - lang = get_xml_text_content(xml_ctx, xpath_str); + lang = linphone_get_xml_text_content(xml_ctx, xpath_str); note = linphone_presence_note_new(note_str, lang); presence_model_add_note(model, note); - if (lang != NULL) free_xml_text_content(lang); - free_xml_text_content(note_str); + if (lang != NULL) linphone_free_xml_text_content(lang); + linphone_free_xml_text_content(note_str); } } if (note_object != NULL) xmlXPathFreeObject(note_object); @@ -1491,7 +1404,7 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing LinphonePresenceModel *model = NULL; int err; - if (create_xml_xpath_context(xml_ctx) < 0) + if (linphone_create_xml_xpath_context(xml_ctx) < 0) return NULL; model = linphone_presence_model_new(); @@ -1606,15 +1519,15 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c } if (strcmp(content_subtype, "pidf+xml") == 0) { - xml_ctx = xmlparsing_context_new(); - xmlSetGenericErrorFunc(xml_ctx, xmlparsing_genericxml_error); + xml_ctx = linphone_xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error); xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0); if (xml_ctx->doc != NULL) { model = process_pidf_xml_presence_notification(xml_ctx); } else { ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer); } - xmlparsing_context_destroy(xml_ctx); + linphone_xmlparsing_context_destroy(xml_ctx); } else { ms_error("Unknown content type '%s/%s' for presence", content_type, content_subtype); } diff --git a/coreapi/private.h b/coreapi/private.h index 5225b6a3c..012484c1d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -338,6 +338,7 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len); void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); +void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing); void linphone_core_play_tone(LinphoneCore *lc); @@ -426,12 +427,22 @@ struct _LinphoneAuthInfo bool_t works; }; +typedef enum _LinphoneIsComposingState { + LinphoneIsComposingIdle, + LinphoneIsComposingActive +} LinphoneIsComposingState; + struct _LinphoneChatRoom{ struct _LinphoneCore *lc; char *peer; LinphoneAddress *peer_url; void * user_data; MSList *messages_hist; + LinphoneIsComposingState remote_is_composing; + LinphoneIsComposingState is_composing; + belle_sip_source_t *remote_composing_refresh_timer; + belle_sip_source_t *composing_idle_timer; + belle_sip_source_t *composing_refresh_timer; }; @@ -788,6 +799,35 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); + +/***************************************************************************** + * XML UTILITY FUNCTIONS * + ****************************************************************************/ + +#include +#include +#include +#include + +#define XMLPARSING_BUFFER_LEN 2048 +#define MAX_XPATH_LENGTH 256 + +typedef struct _xmlparsing_context { + xmlDoc *doc; + xmlXPathContextPtr xpath_ctx; + char errorBuffer[XMLPARSING_BUFFER_LEN]; + char warningBuffer[XMLPARSING_BUFFER_LEN]; +} xmlparsing_context_t; + +xmlparsing_context_t * linphone_xmlparsing_context_new(void); +void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx); +void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...); +int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx); +char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +void linphone_free_xml_text_content(const char *text); +xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); + + #ifdef __cplusplus } #endif diff --git a/coreapi/xml.c b/coreapi/xml.c new file mode 100644 index 000000000..b4b994174 --- /dev/null +++ b/coreapi/xml.c @@ -0,0 +1,98 @@ +/* +linphone +Copyright (C) 2010-2013 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "private.h" + +#include +#include +#include +#include + + +xmlparsing_context_t * linphone_xmlparsing_context_new(void) { + xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t)); + if (xmlCtx != NULL) { + xmlCtx->doc = NULL; + xmlCtx->xpath_ctx = NULL; + xmlCtx->errorBuffer[0] = '\0'; + xmlCtx->warningBuffer[0] = '\0'; + } + return xmlCtx; +} + +void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx) { + if (ctx->doc != NULL) { + xmlFreeDoc(ctx->doc); + ctx->doc = NULL; + } + if (ctx->xpath_ctx != NULL) { + xmlXPathFreeContext(ctx->xpath_ctx); + ctx->xpath_ctx = NULL; + } + free(ctx); +} + +void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) { + xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx; + int sl = strlen(xmlCtx->errorBuffer); + va_list args; + va_start(args, fmt); + vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args); + va_end(args); +} + +int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx) { + if (xml_ctx->xpath_ctx != NULL) { + xmlXPathFreeContext(xml_ctx->xpath_ctx); + } + xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc); + if (xml_ctx->xpath_ctx == NULL) return -1; + return 0; +} + +char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { + xmlXPathObjectPtr xpath_obj; + xmlChar *text = NULL; + int i; + + xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); + if (xpath_obj != NULL) { + if (xpath_obj->nodesetval != NULL) { + xmlNodeSetPtr nodes = xpath_obj->nodesetval; + for (i = 0; i < nodes->nodeNr; i++) { + xmlNodePtr node = nodes->nodeTab[i]; + if (node->children != NULL) { + text = xmlNodeListGetString(xml_ctx->doc, node->children, 1); + } + } + } + xmlXPathFreeObject(xpath_obj); + } + + return (char *)text; +} + +void linphone_free_xml_text_content(const char *text) { + xmlFree((xmlChar *)text); +} + +xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) { + return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx); +} diff --git a/gtk/chat.c b/gtk/chat.c index b44605ae3..0c9aa400b 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -279,6 +279,16 @@ static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageS update_chat_state_message(state,msg); } +void linphone_gtk_compose_text(void) { + GtkWidget *main_window=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); + GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); + LinphoneChatRoom *cr=g_object_get_data(G_OBJECT(w),"cr"); + if (cr) { + linphone_chat_room_compose(cr); + } +} + void linphone_gtk_send_text(){ GtkWidget *main_window=linphone_gtk_get_main_window(); GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list"); @@ -293,7 +303,11 @@ void linphone_gtk_send_text(){ linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL); linphone_gtk_push_text(w,linphone_chat_message_get_from(msg), TRUE,cr,msg,FALSE); + + // Disconnect and reconnect the "changed" signal to prevent triggering it when clearing the text entry. + g_signal_handlers_disconnect_by_func(G_OBJECT(entry),(GCallback)linphone_gtk_compose_text,NULL); gtk_entry_set_text(GTK_ENTRY(entry),""); + g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL); } } @@ -410,6 +424,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres g_signal_connect_swapped(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_send_text,NULL); entry = linphone_gtk_get_widget(chat_view,"text_entry"); g_signal_connect_swapped(G_OBJECT(entry),"activate",(GCallback)linphone_gtk_send_text,NULL); + g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL); g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,NULL); ms_free(with_str); return chat_view; @@ -417,7 +432,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){ char *tmp=linphone_address_as_string(with); - LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),tmp); + LinphoneChatRoom *cr=linphone_core_get_or_create_chat_room(linphone_gtk_get_core(),tmp); ms_free(tmp); return cr; } @@ -516,3 +531,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, linphone_gtk_show_friends(); } + +void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + linphone_gtk_friend_list_update_chat_picture(); +} diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 523cf13b3..0316dd699 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -87,6 +87,18 @@ static GdkPixbuf *create_chat_picture(){ return pixbuf; } +static GdkPixbuf *create_composing_unread_msg(){ + GdkPixbuf *pixbuf; + pixbuf = create_pixbuf("composing_active_chat.png"); + return pixbuf; +} + +static GdkPixbuf *create_composing_chat_picture(){ + GdkPixbuf *pixbuf; + pixbuf = create_pixbuf("composing_chat.png"); + return pixbuf; +} + /* void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){ GtkTreeIter iter; @@ -227,15 +239,23 @@ void linphone_gtk_friend_list_update_chat_picture(){ GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); LinphoneChatRoom *cr=NULL; + bool_t is_composing; int nbmsg=0; if (gtk_tree_model_get_iter_first(model,&iter)) { do{ gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); nbmsg=linphone_chat_room_get_unread_messages_count(cr); + is_composing=linphone_chat_room_is_remote_composing(cr); if(nbmsg != 0){ - gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1); + if (is_composing == TRUE) + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_unread_msg(),-1); + else + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1); } else { - gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1); + if (is_composing == TRUE) + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_chat_picture(),-1); + else + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1); } }while(gtk_tree_model_iter_next(model,&iter)); } diff --git a/gtk/linphone.h b/gtk/linphone.h index 1d674f876..f9d918c51 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -116,6 +116,7 @@ void linphone_gtk_send_text(); GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with); LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with); void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg); +void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); void linphone_gtk_friend_list_update_chat_picture(); void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); diff --git a/gtk/main.c b/gtk/main.c index 135dfe5f4..e47af7f3a 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -266,6 +266,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.call_log_updated=linphone_gtk_call_log_updated; //vtable.text_received=linphone_gtk_text_received; vtable.message_received=linphone_gtk_text_received; + vtable.is_composing_received=linphone_gtk_is_composing_received; vtable.refer_received=linphone_gtk_refer_received; vtable.buddy_info_updated=linphone_gtk_buddy_info_updated; vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; diff --git a/include/sal/sal.h b/include/sal/sal.h index b76d70b05..6044205be 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mscommon.h" #include "ortp/ortp_srtp.h" +#include "belle-sip/belle-sip.h" #ifndef LINPHONE_PUBLIC #define LINPHONE_PUBLIC MS2_PUBLIC @@ -224,6 +225,11 @@ typedef struct SalMessage{ time_t time; }SalMessage; +typedef struct SalIsComposing { + const char *from; + const char *text; +} SalIsComposing; + #define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 SalMediaDescription *sal_media_description_new(); @@ -390,6 +396,7 @@ 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 (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing); 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); @@ -425,6 +432,7 @@ typedef struct SalCallbacks{ SalOnRefer refer_received; SalOnTextReceived text_received; SalOnTextDeliveryUpdate text_delivery_update; + SalOnIsComposingReceived is_composing_received; SalOnNotifyRefer notify_refer; SalOnSubscribeReceived subscribe_received; SalOnSubscribeClosed subscribe_closed; @@ -690,6 +698,8 @@ 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); +belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name); +void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer); int sal_body_has_type(const SalBody *body, const char *type, const char *subtype); /*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/ diff --git a/pixmaps/Makefile.am b/pixmaps/Makefile.am index 2386d68cf..5e9b7a177 100644 --- a/pixmaps/Makefile.am +++ b/pixmaps/Makefile.am @@ -11,7 +11,7 @@ status-orange.png \ status-red.png \ status-offline.png \ call.png \ -chat.png active_chat.png\ +chat.png active_chat.png composing_chat.png composing_active_chat.png\ chat_message_inprogress.png chat_message_delivered.png chat_message_not_delivered.png\ contact-orange.png dialer-orange.png history-orange.png\ startcall-green.png startcall-small.png stopcall-red.png stopcall-small.png addcall-green.png linphone.icns \ diff --git a/pixmaps/active_chat.png b/pixmaps/active_chat.png index d82b7c595c8a90fddb3c313be4bd9c6c524b0af4..ef3cedd1d2cf251b517f1b9840dd0d36b457fcb1 100644 GIT binary patch delta 696 zcmV;p0!RJV8oC;gBe6JK3J(TiOGiWi000000Qp0^e~}>qD4Uwwy}jFX%J`#MGH65&myEE zs1~*?C~Vh25Co>i5QQcZ*+#5JMj80B(9N%eWjLrCDd;}dhi}!us zyXQOiUcM_NfAO!OZ1hKS`~iFy4q-Mj3hVo`$_BSkM0mtE)^Y6aIEp=0ICC%POhhXz zK>zcAQeAyt`MlXX@7*aTP>Q;P-q)?gek{(sQ5AhF06@(aps%lwB4R6IY{`eWtO8>b zbNKXb8m{sR;ENl3evP&-gvZL3k=K$~O!xrY0LfMKfBXH6#bQh*lQd0pO@>Ebu}lGh zGG9EtJaP+XA)k#kdP9k65(j!7Zr+;{svDhT*cWfg7?mhqT$)zC{ zWv$72U6qca@&oudJ%PvV1E{ZZ!=(T>+geZ_slrR{yGj$$tWJ7+d+7wBsVNQ*4KY2Y zl35aG&rH6mA`*?-KPyf})Vw?-5{cDo8wr%{eRiOGIYb1OW!a}Il}b5E zS3DkvrfI8%|F#|s1{n&4pzAse!$56qEdXF-WCYP@6e0o<`IEAhTU(X|lCUfbjg5_x zk>9o0)zw9k3B(A?ZCPRFnO e8rL&E7yJhK0Wf%d8%Lf10000 z06Lfe02gnPU&TfM00M$ZL_t(|+RRm7NK;W9{?7H&?sR*hEdn_pGtw9h3rpAau6N&6atfrF)f+(~?t4Su)muh26i$Iu=6X6-y{+OT-gi0M|is1$;gqqtPfW%c5zT z84((L#R>%kQs6G5D`mZ{<<1PrbSAp4!|8OcEtgS_o4!ZbG(Uls3)f(pN#JJ)a{$VA zR>M?_Z_Q49`v3rGOrG}kGN)QHd1hZRp@0H{LMvi>*9gxJ{1Wa-_?D9Xo}~#~YxTF}&!!4J#Hp(RAdHZp)-M2PWaKZ|N3-fKK1YEThry zY}~$;0J!Je!zUMqSz_zSTB%B{lFI$~I6aBS9fN4BalxqoH*U3|GF*d~+({Rnm8PeoS6tAAf?RCB$-U+C08sKgQjUK8?W{t5C||B3_{m+7>0rR z`g#Ds=;$aSkqCqk5JD_V^!L?LN|1z<63xxcBF*Sb=Q%{fhtkkI$w43;=loR6owzNErYC002ov JPDHLkV1n*lRrde@ diff --git a/pixmaps/composing_active_chat.png b/pixmaps/composing_active_chat.png new file mode 100644 index 0000000000000000000000000000000000000000..77da9e37f79077c2eba5ac6ef2077a8867cfbdb0 GIT binary patch literal 3398 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 literal 0 HcmV?d00001 diff --git a/pixmaps/composing_chat.png b/pixmaps/composing_chat.png new file mode 100644 index 0000000000000000000000000000000000000000..2d329ed21dccdfa12ce40308e8e2e22336faec20 GIT binary patch literal 3291 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 literal 0 HcmV?d00001 diff --git a/tester/Makefile.am b/tester/Makefile.am index 4388ac483..ba8432bfa 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -23,11 +23,11 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi -LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) +LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) $(LIBXML2_LIBS) AM_LDFLAGS=$(CUNIT_LIBS) -AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) +AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) test: liblinphone_tester ./liblinphone_tester --config $(abs_srcdir) From e022b0d3ff20d7115c366d8b31f90fb402fbeab8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 3 Jan 2014 15:34:03 +0100 Subject: [PATCH 083/439] Add Android wrapper for RFC3994. --- build/android/Android.mk | 3 ++- coreapi/linphonecore_jni.cc | 22 +++++++++++++++++++ .../org/linphone/core/LinphoneChatRoom.java | 11 ++++++++++ .../linphone/core/LinphoneCoreListener.java | 7 ++++++ .../linphone/core/LinphoneChatRoomImpl.java | 10 +++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index e9c9fa1f6..9263f748f 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -60,7 +60,8 @@ LOCAL_SRC_FILES := \ linphone_tunnel_config.c \ message_storage.c \ info.c \ - event.c + event.c \ + xml.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 4dc3b6d04..a1f428b4a 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -170,6 +170,7 @@ public: vTable.call_encryption_changed = callEncryptionChange; vTable.text_received = text_received; vTable.message_received = message_received; + vTable.is_composing_received = is_composing_received; vTable.dtmf_received = dtmf_received; vTable.new_subscription_requested = new_subscription_requested; vTable.notify_presence_received = notify_presence_received; @@ -225,6 +226,7 @@ public: /*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/ textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V"); messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V"); + isComposingReceivedId = env->GetMethodID(listenerClass,"isComposingReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;)V"); dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V"); infoReceivedId = env->GetMethodID(listenerClass,"infoReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneInfoMessage;)V"); @@ -307,6 +309,7 @@ public: jmethodID notifyPresenceReceivedId; jmethodID textReceivedId; jmethodID messageReceivedId; + jmethodID isComposingReceivedId; jmethodID dtmfReceivedId; jmethodID callStatsUpdatedId; jmethodID transferStateId; @@ -550,6 +553,19 @@ public: ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) ,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg)); } + static void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener + ,lcData->isComposingReceivedId + ,lcData->core + ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room)); + } static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); @@ -2311,6 +2327,12 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteHistory(JNIEnv ,jlong ptr) { linphone_chat_room_delete_history((LinphoneChatRoom*)ptr); } +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneChatRoomImpl_compose(JNIEnv *env, jobject thiz, jlong ptr) { + linphone_chat_room_compose((LinphoneChatRoom *)ptr); +} +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneChatRoomImpl_isRemoteComposing(JNIEnv *env, jobject thiz, jlong ptr) { + return (jboolean)linphone_chat_room_is_remote_composing((LinphoneChatRoom *)ptr); +} extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteMessage(JNIEnv* env ,jobject thiz ,jlong room diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index 5c87f5647..e84538269 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -80,6 +80,17 @@ public interface LinphoneChatRoom { * Deletes all the messages associated with the peer of this chat room */ void deleteHistory(); + + /** + * Notify the destination of the chat message being composed that the user is typing a new message. + */ + void compose(); + + /** + * Tells whether the remote is currently composing a message. + * @return true if the remote is currently composing a message, false otherwise. + */ + boolean isRemoteComposing(); /** * Marks all the messages in this conversation as read diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index 60e9e3d59..d01fa01a7 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -91,6 +91,13 @@ public interface LinphoneCoreListener { */ void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message); + /** + * invoked when a composing notification is received + * @param lc LinphoneCore + * @param room LinphoneChatRoom involved in the conversation. + */ + void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr); + /** * invoked when a new dtmf is received * @param lc LinphoneCore diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 7f4d684ee..c2021e379 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -31,6 +31,8 @@ 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 compose(long ptr); + private native boolean isRemoteComposing(long ptr); private native void markAsRead(long ptr); private native void deleteMessage(long room, long message); private native void updateUrl(long room, long message); @@ -87,6 +89,14 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public void deleteHistory() { deleteHistory(nativePtr); } + + public void compose() { + compose(nativePtr); + } + + public boolean isRemoteComposing() { + return isRemoteComposing(nativePtr); + } public void markAsRead() { markAsRead(nativePtr); From 452b004655fb9e7e4a4586896ee321121b9f1e57 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 3 Jan 2014 15:01:11 +0100 Subject: [PATCH 084/439] Add CMakeLists.txt to compile using cmake. --- CMakeLists.txt | 57 ++++++++++++++++++++++ coreapi/CMakeLists.txt | 99 ++++++++++++++++++++++++++++++++++++++ share/CMakeLists.txt | 17 +++++++ share/rings/CMakeLists.txt | 4 ++ 4 files changed, 177 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 coreapi/CMakeLists.txt create mode 100644 share/CMakeLists.txt create mode 100644 share/rings/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..7af5d50ac --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 2.6) +project(LINPHONE C) + +if(NOT ORTP_ROOT_DIR) + set(ORTP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/oRTP) +endif() +if(NOT ORTP_INCLUDE_DIR) + set(ORTP_INCLUDE_DIR ${ORTP_ROOT_DIR}/include) +endif() +if(NOT MS2_ROOT_DIR) + set(MS2_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mediastreamer2) +endif() +if(NOT MS2_INCLUDE_DIR) + set(MS2_INCLUDE_DIR ${MS2_ROOT_DIR}/include) +endif() +if(NOT LIBXML2_ROOT_DIR) + set(LIBXML2_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libxml2) +endif() +if(NOT LIBXML2_INCLUDE_DIR) + set(LIBXML2_INCLUDE_DIR ${LIBXML2_ROOT_DIR}/include) +endif() +if(NOT BELLESIP_ROOT_DIR) + set(BELLESIP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../belle-sip) +endif() +if(NOT BELLESIP_INCLUDE_DIR) + set(BELLESIP_INCLUDE_DIR ${BELLESIP_ROOT_DIR}/include) +endif() + +include_directories( + include/ + coreapi/ + ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/libxml2/ +) + +if(USE_INSTALLED_COMPONENTS) + include_directories( + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/include/libxml2 + ) +else() + include_directories( + ${ORTP_INCLUDE_DIR} + ${MS2_INCLUDE_DIR} + ${LIBXML2_INCLUDE_DIR} + ${BELLESIP_INCLUDE_DIR} + ) + if(WIN32) + include_directories(${ORTP_ROOT_DIR}/build/vsx/oRTP/oRTP/) + endif(WIN32) +endif() + +add_subdirectory(coreapi) +add_subdirectory(share) + +if(INSTALL_COMPONENT_IN_POSTBUILD) + add_install_target(INSTALL_liblinphone COMP_liblinphone liblinphone) +endif() diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt new file mode 100644 index 000000000..a007317c5 --- /dev/null +++ b/coreapi/CMakeLists.txt @@ -0,0 +1,99 @@ +set(SOURCE_FILES + address.c + authentication.c + bellesip_sal/sal_address_impl.c + bellesip_sal/sal_impl.c + bellesip_sal/sal_op_call.c + bellesip_sal/sal_op_call_transfer.c + bellesip_sal/sal_op_events.c + bellesip_sal/sal_op_impl.c + bellesip_sal/sal_op_info.c + bellesip_sal/sal_op_message.c + bellesip_sal/sal_op_presence.c + bellesip_sal/sal_op_publish.c + bellesip_sal/sal_op_registration.c + bellesip_sal/sal_sdp.c + callbacks.c + chat.c + conference.c + ec-calibrator.c + enum.c + event.c + friend.c + info.c + linphonecall.c + linphonecore.c + #linphone_tunnel.cc + linphone_tunnel_stubs.c + linphone_tunnel_config.c + lpconfig.c + lsd.c + message_storage.c + misc.c + offeranswer.c + presence.c + proxy.c + sal.c + siplogin.c + sipsetup.c + #TunnelManager.cc + bellesip_sal/sal_impl.h + enum.h + event.h + linphonecore.h + linphonecore_utils.h + linphonefriend.h + linphone_tunnel.h + lpconfig.h + offeranswer.h + private.h + sipsetup.h +) + +add_definitions( + -D_TRUE_TIME + -DIN_LINPHONE + -DUSE_BELLESIP + #-DTUNNEL_ENABLED + #-DVIDEO_ENABLED + -DLINPHONE_PACKAGE_NAME="linphone" + -DLINPHONE_VERSION="Devel" + -DLIBLINPHONE_EXPORTS + -DLINPHONE_PLUGINS_DIR="" +) + +if(WIN32) +add_definitions( + -DWINDOW_NATIVE +) + +set(LIBS ws2_32) +endif(WIN32) +set(LIBS ${LIBS} libortp libmediastreamer_base libmediastreamer_voip libbellesip libxml2) + +add_library(liblinphone SHARED ${SOURCE_FILES}) +set_target_properties(liblinphone PROPERTIES VERSION 3.6.99 SOVERSION 5) + +target_link_libraries(liblinphone ${LIBS}) + +install(TARGETS liblinphone + COMPONENT COMP_liblinphone + DESTINATION ${LIB_INSTALL_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + +if(USE_INSTALLED_COMPONENTS) + add_dependencies(liblinphone + INSTALL_libortp + INSTALL_libmediastreamer2 + INSTALL_libbellesip + INSTALL_libxml2) +endif() + + + +file(GLOB HEADER_FILES "*.h") + +install(FILES ${HEADER_FILES} + COMPONENT COMP_liblinphone + DESTINATION include/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt new file mode 100644 index 000000000..8d15a6f5c --- /dev/null +++ b/share/CMakeLists.txt @@ -0,0 +1,17 @@ +install(FILES archived-rootca.pem + RENAME rootca.pem + COMPONENT COMP_liblinphone + DESTINATION share/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + +install(FILES ringback.wav + COMPONENT COMP_liblinphone + DESTINATION share/sounds/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + +add_subdirectory(rings) + +install(FILES ../mediastreamer2/src/voip/nowebcamCIF.jpg + COMPONENT COMP_liblinphone + DESTINATION share/images + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) diff --git a/share/rings/CMakeLists.txt b/share/rings/CMakeLists.txt new file mode 100644 index 000000000..cf359bb4e --- /dev/null +++ b/share/rings/CMakeLists.txt @@ -0,0 +1,4 @@ +install(FILES oldphone.wav toy-mono.wav + COMPONENT COMP_liblinphone + DESTINATION share/sounds/linphone/rings + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) From d57e2b3cb7e69e44eb32e9a60dfe6a5f6237120e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 3 Jan 2014 15:27:55 +0100 Subject: [PATCH 085/439] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 4103f0b1d..cd4838bc3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4103f0b1d7757558d06e6e32b657308bb2556c9b +Subproject commit cd4838bc3ec1921ddab8e25b8101c53bedbef00c diff --git a/oRTP b/oRTP index 37b81a118..db393f57c 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 37b81a118760caa22a5a89d56945acea9aa52523 +Subproject commit db393f57ca12744f783b9e51776ea8897ba242d1 From d43eb3788e66f2007368e6f72f88db9a208c920f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 3 Jan 2014 17:32:42 +0100 Subject: [PATCH 086/439] Fix liblinphone wp8 build --- build/vsx/LibLinphone/LibLinphone.vcxproj | 5 +++-- coreapi/linphonecall.c | 9 ++++++++- coreapi/linphonecore.h | 5 ++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index c2d421126..9bc9aadf9 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -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="";UNICODE;%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) 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="";UNICODE;%(PreprocessorDefinitions) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) true true Default @@ -207,6 +207,7 @@ + diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4510ef12f..aa19496ce 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2572,6 +2572,13 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { return call->params.in_conference; } +AudioStream* linphone_call_get_audiostream(LinphoneCall* call) { + return call->audiostream; +} + +VideoStream* linphone_call_get_videostream(LinphoneCall* call) { + return call->videostream; +} /** * Perform a zoom of the video displayed during a call. @@ -2688,4 +2695,4 @@ void linphone_call_set_contact_op(LinphoneCall* call) { sal_op_set_contact(call->op, contact); linphone_address_destroy(contact); } -} +} \ No newline at end of file diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4aa4d0942..4b97eaf88 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "ortp/payloadtype.h" #include "mediastreamer2/mscommon.h" #include "mediastreamer2/msvideo.h" +#include "mediastreamer2/mediastream.h" #ifdef IN_LINPHONE #include "sipsetup.h" @@ -580,7 +581,6 @@ struct _LinphoneCallStats { LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); - /** Callback prototype */ typedef void (*LinphoneCallCbFunc)(LinphoneCall *call,void * user_data); @@ -652,6 +652,9 @@ LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state(LinphoneCall LINPHONE_PUBLIC void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy); LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); +LINPHONE_PUBLIC AudioStream * linphone_call_get_audiostream(LinphoneCall *call); +LINPHONE_PUBLIC VideoStream * linphone_call_get_videostream(LinphoneCall *call); + /** * Return TRUE if this call is currently part of a conference * @param call #LinphoneCall From be96cb432e8ec0f821b9bc45402b34a001a97d21 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Jan 2014 11:48:27 +0100 Subject: [PATCH 087/439] Reverted previous commit and added call stats functions to linphone API --- coreapi/linphonecall.c | 113 ++++++++++++++++++++++++++++++++++++++--- coreapi/linphonecore.h | 7 ++- 2 files changed, 110 insertions(+), 10 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index aa19496ce..17d8a8ede 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2247,6 +2247,111 @@ const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { return stats; } +float linphone_call_stats_update_sender_loss_rate(LinphoneCallStats *stats) { + const report_block_t *srb = NULL; + + if (!stats || !stats->sent_rtcp) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->sent_rtcp->b_cont != NULL) + msgpullup(stats->sent_rtcp, -1); + if (rtcp_is_SR(stats->sent_rtcp)) + srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); + else if (rtcp_is_RR(stats->sent_rtcp)) + srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); + if (!srb) + return 0.0; + return 100.0 * report_block_get_fraction_lost(srb) / 256.0; +} + +float linphone_call_stats_update_receiver_loss_rate(LinphoneCallStats *stats) { + const report_block_t *rrb = NULL; + + if (!stats || !stats->received_rtcp) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->received_rtcp->b_cont != NULL) + msgpullup(stats->received_rtcp, -1); + if (rtcp_is_RR(stats->received_rtcp)) + rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); + else if (rtcp_is_SR(stats->received_rtcp)) + rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); + if (!rrb) + return 0.0; + return 100.0 * report_block_get_fraction_lost(rrb) / 256.0; +} + +float linphone_call_stats_update_sender_interarrival_jitter(LinphoneCallStats *stats, LinphoneCall *call) { + const LinphoneCallParams *params; + const PayloadType *pt; + const report_block_t *srb = NULL; + + if (!stats || !call || !stats->sent_rtcp) + return 0.0; + params = linphone_call_get_current_params(call); + if (!params) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->sent_rtcp->b_cont != NULL) + msgpullup(stats->sent_rtcp, -1); + if (rtcp_is_SR(stats->sent_rtcp)) + srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); + else if (rtcp_is_RR(stats->sent_rtcp)) + srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); + if (!srb) + return 0.0; + if (stats->type == LINPHONE_CALL_STATS_AUDIO) + pt = linphone_call_params_get_used_audio_codec(params); + else + pt = linphone_call_params_get_used_video_codec(params); + if (!pt || (pt->clock_rate == 0)) + return 0.0; + return (float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate; +} + +float linphone_call_stats_update_receiver_interarrival_jitter(LinphoneCallStats *stats, LinphoneCall *call) { + const LinphoneCallParams *params; + const PayloadType *pt; + const report_block_t *rrb = NULL; + + if (!stats || !call || !stats->received_rtcp) + return 0.0; + params = linphone_call_get_current_params(call); + if (!params) + return 0.0; + /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ + if (stats->received_rtcp->b_cont != NULL) + msgpullup(stats->received_rtcp, -1); + if (rtcp_is_SR(stats->received_rtcp)) + rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); + else if (rtcp_is_RR(stats->received_rtcp)) + rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); + if (!rrb) + return 0.0; + if (stats->type == LINPHONE_CALL_STATS_AUDIO) + pt = linphone_call_params_get_used_audio_codec(params); + else + pt = linphone_call_params_get_used_video_codec(params); + if (!pt || (pt->clock_rate == 0)) + return 0.0; + return (float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate; +} + +uint64_t linphone_call_stats_update_late_packets_cumulative_number(LinphoneCallStats *stats, LinphoneCall *call) { + rtp_stats_t rtp_stats; + + if (!stats || !call) + return 0; + memset(&rtp_stats, 0, sizeof(rtp_stats)); + if (stats->type == LINPHONE_CALL_STATS_AUDIO) + audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats); +#ifdef VIDEO_ENABLED + else + video_stream_get_local_rtp_stats(call->videostream, &rtp_stats); +#endif + return rtp_stats.outoftime; +} + /** * Enable recording of the call (voice-only). * This function must be used before the call parameters are assigned to the call. @@ -2572,14 +2677,6 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { return call->params.in_conference; } -AudioStream* linphone_call_get_audiostream(LinphoneCall* call) { - return call->audiostream; -} - -VideoStream* linphone_call_get_videostream(LinphoneCall* call) { - return call->videostream; -} - /** * Perform a zoom of the video displayed during a call. * @param call the call. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4b97eaf88..83fa35994 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -580,6 +580,11 @@ struct _LinphoneCallStats { LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_stats_update_sender_loss_rate(const LinphoneCallStats *stats); +LINPHONE_PUBLIC float linphone_call_stats_update_receiver_loss_rate(const LinphoneCallStats *stats); +LINPHONE_PUBLIC float linphone_call_stats_update_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_stats_update_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call); +LINPHONE_PUBLIC uint64_t linphone_call_stats_update_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call); /** Callback prototype */ typedef void (*LinphoneCallCbFunc)(LinphoneCall *call,void * user_data); @@ -652,8 +657,6 @@ LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state(LinphoneCall LINPHONE_PUBLIC void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy); LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call); -LINPHONE_PUBLIC AudioStream * linphone_call_get_audiostream(LinphoneCall *call); -LINPHONE_PUBLIC VideoStream * linphone_call_get_videostream(LinphoneCall *call); /** * Return TRUE if this call is currently part of a conference From 58d9e149cd939795c17f184b11af2281cebc5155 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Jan 2014 15:08:56 +0100 Subject: [PATCH 088/439] Fix compilation with cmake. --- coreapi/CMakeLists.txt | 1 + mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index a007317c5..74e80dfc0 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -37,6 +37,7 @@ set(SOURCE_FILES siplogin.c sipsetup.c #TunnelManager.cc + xml.c bellesip_sal/sal_impl.h enum.h event.h diff --git a/mediastreamer2 b/mediastreamer2 index cd4838bc3..7451aeb8a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit cd4838bc3ec1921ddab8e25b8101c53bedbef00c +Subproject commit 7451aeb8a2ff0d709949b671a06a8ebd287c81b5 From a3f096723623378248160c045f9c7af40779fb46 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Jan 2014 15:42:34 +0100 Subject: [PATCH 089/439] Add missing is_composing_received callback when a text message is received. --- coreapi/chat.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index ddb6ba262..186aa111f 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -198,7 +198,10 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, //legacy API if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message); if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg); - + if (cr->lc->vtable.is_composing_received != NULL) { + cr->remote_is_composing = LinphoneIsComposingIdle; + cr->lc->vtable.is_composing_received(cr->lc, cr); + } } /** From aeb99d09d9a963e9c4f669b1dbf0f2c86e0088c6 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 6 Jan 2014 15:45:21 +0100 Subject: [PATCH 090/439] Fix compilation (missing const keywords). --- coreapi/linphonecall.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 17d8a8ede..19d4eaa96 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2247,7 +2247,7 @@ const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { return stats; } -float linphone_call_stats_update_sender_loss_rate(LinphoneCallStats *stats) { +float linphone_call_stats_update_sender_loss_rate(const LinphoneCallStats *stats) { const report_block_t *srb = NULL; if (!stats || !stats->sent_rtcp) @@ -2264,7 +2264,7 @@ float linphone_call_stats_update_sender_loss_rate(LinphoneCallStats *stats) { return 100.0 * report_block_get_fraction_lost(srb) / 256.0; } -float linphone_call_stats_update_receiver_loss_rate(LinphoneCallStats *stats) { +float linphone_call_stats_update_receiver_loss_rate(const LinphoneCallStats *stats) { const report_block_t *rrb = NULL; if (!stats || !stats->received_rtcp) @@ -2281,7 +2281,7 @@ float linphone_call_stats_update_receiver_loss_rate(LinphoneCallStats *stats) { return 100.0 * report_block_get_fraction_lost(rrb) / 256.0; } -float linphone_call_stats_update_sender_interarrival_jitter(LinphoneCallStats *stats, LinphoneCall *call) { +float linphone_call_stats_update_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { const LinphoneCallParams *params; const PayloadType *pt; const report_block_t *srb = NULL; @@ -2309,7 +2309,7 @@ float linphone_call_stats_update_sender_interarrival_jitter(LinphoneCallStats *s return (float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate; } -float linphone_call_stats_update_receiver_interarrival_jitter(LinphoneCallStats *stats, LinphoneCall *call) { +float linphone_call_stats_update_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { const LinphoneCallParams *params; const PayloadType *pt; const report_block_t *rrb = NULL; @@ -2337,7 +2337,7 @@ float linphone_call_stats_update_receiver_interarrival_jitter(LinphoneCallStats return (float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate; } -uint64_t linphone_call_stats_update_late_packets_cumulative_number(LinphoneCallStats *stats, LinphoneCall *call) { +uint64_t linphone_call_stats_update_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call) { rtp_stats_t rtp_stats; if (!stats || !call) From 13ac82f0663e2c9054852971481a3fe92f26868e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 6 Jan 2014 16:18:58 +0100 Subject: [PATCH 091/439] Fixed tutorials for android --- .../org/linphone/core/tutorials/TutorialBuddyStatus.java | 6 ++++++ .../org/linphone/core/tutorials/TutorialChatRoom.java | 8 ++++++++ .../org/linphone/core/tutorials/TutorialHelloWorld.java | 6 ++++++ .../org/linphone/core/tutorials/TutorialRegistration.java | 6 ++++++ 4 files changed, 26 insertions(+) diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index 53b9331fb..c41ca2933 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -280,5 +280,11 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + // 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 371b9af8e..3278c990d 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -202,5 +202,13 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa } + @Override + public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + if (cr.isRemoteComposing()) + write("Remote is writing a message"); + else + write("Remote has stop writing"); + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index e8ba341ad..763e18f12 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -206,5 +206,11 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } + @Override + public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + // 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 93aa87d04..8384ed16e 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -237,6 +237,12 @@ public class TutorialRegistration implements LinphoneCoreListener { } + @Override + public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) { + // TODO Auto-generated method stub + + } + } From 95246f5161d047163e1afd2e967244da6725b9a1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 6 Jan 2014 16:34:19 +0100 Subject: [PATCH 092/439] fix problem with media encryption not set in params for incoming calls --- coreapi/linphonecall.c | 39 +++++++++++---------------------------- coreapi/linphonecore.c | 22 +++++++++++++--------- coreapi/private.h | 1 + 3 files changed, 25 insertions(+), 37 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 19d4eaa96..755260efe 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -595,9 +595,14 @@ 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); + + /* + * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote + * end apparently does not support. This features are: privacy, video, srtp . + */ /*set privacy*/ call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); - + /*set video support */ md=sal_call_get_remote_media_description(op); call->params.has_video &= !!lc->video_policy.automatically_accept; if (md) { @@ -605,6 +610,11 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro // In this case WE chose the media parameters according to policy. call->params.has_video &= linphone_core_media_description_contains_video_stream(md); } + /*Init encryption support*/ + if (call->params.media_encryption==LinphoneMediaEncryptionSRTP && md){ + if (!linphone_core_media_description_has_srtp(md)) call->params.media_encryption=LinphoneMediaEncryptionNone; + } + switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: call->ice_session = ice_session_new(); @@ -2712,28 +2722,16 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, }else ms_warning("Could not apply zoom: video output wasn't activated."); } -#ifndef USE_BELLESIP -static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ -#else static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ -#endif LinphoneAddress *ctt=NULL; -#ifdef USE_BELLESIP LinphoneAddress *ret=NULL; -#else - char* ret; -#endif const char *localip=call->localip; /* first use user's supplied ip address if asked*/ if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ ctt=linphone_core_get_primary_contact_parsed(lc); linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc)); - #ifdef USE_BELLESIP ret=ctt; - #else - ret=linphone_address_as_string(ctt); - #endif } else if (call->op && sal_op_get_contact(call->op)!=NULL){ /* if already choosed, don't change it */ return NULL; @@ -2741,19 +2739,11 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , /* 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){ @@ -2761,16 +2751,9 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , linphone_address_set_domain(ctt,localip); linphone_address_set_port(ctt,linphone_core_get_sip_port(lc)); ms_message("Contact has been fixed using local ip"/* to %s",ret*/); -#ifdef USE_BELLESIP ret=ctt; -#else - ret=linphone_address_as_string_uri_only(ctt); -#endif } } -#ifndef USE_BELLESIP - if (ctt) linphone_address_destroy(ctt); -#endif return ret; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f4773e111..4bebd832a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2873,17 +2873,21 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } -bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ - if (linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP){ - int i; - for(i=0;in_active_streams;i++){ - SalStreamDescription *sd=&md->streams[i]; - if (sd->proto!=SalProtoRtpSavp){ - return TRUE; - } +bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md){ + int i; + if (md->n_active_streams==0) return FALSE; + + for(i=0;in_active_streams;i++){ + const SalStreamDescription *sd=&md->streams[i]; + if (sd->proto!=SalProtoRtpSavp){ + return FALSE; } } - return FALSE; + return TRUE; +} + +bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ + return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !linphone_core_media_description_has_srtp(md); } void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ diff --git a/coreapi/private.h b/coreapi/private.h index 012484c1d..3ce58499f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -320,6 +320,7 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call); void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session); void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md); +bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md); void linphone_core_send_initial_subscribes(LinphoneCore *lc); void linphone_core_write_friends_config(LinphoneCore* lc); From 041e20edfb01f56bbbd03aef184822590455c9f4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 6 Jan 2014 23:24:00 +0100 Subject: [PATCH 093/439] * fix incorrect behavior when the body of an INVITE cannot be understood or parsed. Previously it was answering 200Ok. * do not send 415 but 488 in case of incompatible codecs, which is more correct according to the RFC. 415 should be replied if the body cannot be understood (for example: is not application/sdp) --- coreapi/bellesip_sal/sal_op_call.c | 86 ++++++++++++++++++++++-------- coreapi/bellesip_sal/sal_op_impl.c | 6 +-- coreapi/callbacks.c | 3 +- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 5 +- coreapi/misc.c | 16 +++--- coreapi/sal.c | 2 +- include/sal/sal.h | 6 +-- tester/call_tester.c | 44 +++++++++++++-- tester/liblinphone_tester.c | 2 + 10 files changed, 125 insertions(+), 47 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index a286001b2..024cf5313 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 int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error); + /*used for calls terminated before creation of a dialog*/ static void call_set_released(SalOp* op){ if (!op->call_released){ @@ -84,8 +86,8 @@ static void sdp_process(SalOp *h){ } } } - } + static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) { belle_sip_header_content_type_t* content_type ; belle_sip_header_content_length_t* content_length; @@ -159,10 +161,13 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { belle_sdp_session_description_t* sdp; - if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) { - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - if (op->base.local_media) sdp_process(op); + SalReason reason; + if (extract_sdp(BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { + if (sdp){ + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + if (op->base.local_media) sdp_process(op); + }/*if no sdp in response, what can we do ?*/ } } @@ -322,15 +327,46 @@ 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) { +/* + * Extract the sdp from a sip message. + * If there is no body in the message, the session_desc is set to null, 0 is returned. + * If body was present is not a SDP or parsing of SDP failed, -1 is returned and SalReason is set appropriately. + * +**/ +static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) { + belle_sip_header_content_type_t* content_type=belle_sip_message_get_header_by_type(message,belle_sip_header_content_type_t); + if (content_type){ + if (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("sdp",belle_sip_header_content_type_get_subtype(content_type))==0) { + *session_desc=belle_sdp_session_description_parse(belle_sip_message_get_body(message)); + if (*session_desc==NULL) { + ms_error("Failed to parse SDP message."); + *error=SalReasonNotAcceptable; + return -1; + } + }else{ + *error=SalReasonUnsupportedContent; + return -1; + } + }else *session_desc=NULL; + return 0; +} + +static int 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; + SalReason reason; + if (extract_sdp(BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { + if (sdp){ + op->sdp_offering=FALSE; + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + belle_sip_object_unref(sdp); + }else op->sdp_offering=TRUE; /*INVITE without SDP*/ + return 0; + }else{ + sal_call_decline(op,reason,NULL); + return -1; + } } static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { @@ -415,13 +451,18 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t /*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); + SalReason reason; + if (extract_sdp(BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){ + if (sdp){ + if (op->base.remote_media) + sal_media_description_unref(op->base.remote_media); + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + sdp_process(op); + belle_sip_object_unref(sdp); + }else{ + ms_warning("SDP expected in ACK but not found."); + } } } /*FIXME @@ -445,9 +486,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t sal_media_description_unref(op->result); op->result=NULL; } - process_sdp_for_invite(op,req); - - op->base.root->callbacks.call_updating(op); + if (process_sdp_for_invite(op,req)==0) + op->base.root->callbacks.call_updating(op); } else if (strcmp("INFO",belle_sip_request_get_method(req))==0){ if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)) && strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 47958ac6e..51dec9b01 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -334,7 +334,7 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonForbidden: ret=403; break; - case SalReasonMedia: + case SalReasonUnsupportedContent: ret=415; break; case SalReasonNotFound: @@ -356,7 +356,7 @@ SalReason sal_reason_to_sip_code(SalReason r){ ret=401; break; case SalReasonNotAcceptable: - ret=488; + ret=488; /*or maybe 606 Not Acceptable ?*/ break; case SalReasonNoMatch: ret=481; @@ -385,7 +385,7 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal break; case 415: *sal_err=SalErrorFailure; - *sal_reason=SalReasonMedia; + *sal_reason=SalReasonUnsupportedContent; break; case 422: ms_error ("422 not implemented yet");; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 3ebce7488..c2c382114 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -612,7 +612,8 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (lc->vtable.display_status) lc->vtable.display_status(lc,msg600); break; - case SalReasonMedia: + case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP && !linphone_core_is_media_encryption_mandatory(lc)) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4bebd832a..a378f8366 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2903,7 +2903,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ md=sal_call_get_final_media_description(call->op); if (md){ if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ - sal_call_decline(call->op,SalReasonMedia,NULL); + sal_call_decline(call->op,SalReasonNotAcceptable,NULL); linphone_call_stop_media_streams(call); linphone_core_del_call(lc,call); linphone_call_unref(call); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 83fa35994..7358159a9 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -167,7 +167,7 @@ enum _LinphoneReason{ LinphoneReasonNotFound, /**lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); - /*flexisip will retain the 415 until the "urgent reply" timeout arrives.*/ + /*flexisip will retain the 488 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(linphone_call_get_reason(out_call),LinphoneReasonNotAcceptable); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); linphone_call_unref(out_call); @@ -1387,6 +1387,41 @@ static void call_established_with_rejected_reinvite(void) { linphone_core_manager_destroy(pauline); } +static void call_established_with_rejected_incoming_reinvite(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + /*wait for ACK to be transmitted before going to reINVITE*/ + wait_for_until(marie->lc,pauline->lc,NULL,0,1000); + + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + + linphone_core_update_call(marie->lc + ,linphone_core_get_current_call(marie->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))); + + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(marie->lc)),LinphoneReasonNotAcceptable); + + CU_ASSERT_EQUAL(pauline->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"); @@ -1399,8 +1434,8 @@ static void call_established_with_rejected_reinvite_with_error(void) { 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))); + ,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)); @@ -1460,6 +1495,7 @@ test_t call_tests[] = { { "Call with custom headers",call_with_custom_headers}, { "Call established with rejected INFO",call_established_with_rejected_info}, { "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite}, + { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error} }; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 910cb43b3..a5be38d65 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -136,9 +136,11 @@ bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int va 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,3000); } + bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { int retry=0; MSList* iterator; From dbc88dbbdf31016bac49092aaf8328448c0f2726 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 7 Jan 2014 10:31:37 +0100 Subject: [PATCH 094/439] fix make distcheck --- po/POTFILES.in | 1 + 1 file changed, 1 insertion(+) diff --git a/po/POTFILES.in b/po/POTFILES.in index 8f1c5d3a6..96893ed99 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -27,6 +27,7 @@ gtk/loginframe.c [type: gettext/glade]gtk/call_statistics.ui [type: gettext/glade]gtk/tunnel_config.ui [type: gettext/glade]gtk/keypad.ui +[type: gettext/glade]gtk/ldap.ui coreapi/linphonecore.c coreapi/misc.c coreapi/presence.c From abb7c2d50c948f4ef8715b6d58f0e8eeb43e7845 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 7 Jan 2014 11:45:01 +0100 Subject: [PATCH 095/439] Improved composing_received to prevent loosing the information if the chatroom doesn't exists --- coreapi/chat.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 186aa111f..ee6d66d3c 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -336,14 +336,10 @@ static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const c } void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) { - LinphoneChatRoom *cr = NULL; - LinphoneAddress *addr = linphone_address_new(is_composing->from); - linphone_address_clean(addr); - cr = linphone_core_get_chat_room(lc, addr); + LinphoneChatRoom *cr = linphone_core_get_or_create_chat_room(lc, is_composing->from); if (cr != NULL) { linphone_chat_room_notify_is_composing(cr, is_composing->text); } - linphone_address_destroy(addr); } bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { From fa421af04a2ff4f25f86bef28c3a82ca8062aa1c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 7 Jan 2014 14:40:54 +0100 Subject: [PATCH 096/439] fix problem with SRTP proposed during pauses (by GTK app, due to the use of linphone_core_accept_call_with_params()). --- coreapi/linphonecall.c | 35 +++++++++++++++-------------------- coreapi/linphonecore.c | 1 + 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 755260efe..b386a3e33 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -598,7 +598,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro /* * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote - * end apparently does not support. This features are: privacy, video, srtp . + * end apparently does not support. This features are: privacy, video */ /*set privacy*/ call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); @@ -610,10 +610,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro // In this case WE chose the media parameters according to policy. call->params.has_video &= linphone_core_media_description_contains_video_stream(md); } - /*Init encryption support*/ - if (call->params.media_encryption==LinphoneMediaEncryptionSRTP && md){ - if (!linphone_core_media_description_has_srtp(md)) call->params.media_encryption=LinphoneMediaEncryptionNone; - } switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: @@ -1770,21 +1766,20 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna /* valid local tags are > 0 */ if (stream->proto == SalProtoRtpSavp) { - local_st_desc=sal_media_description_find_stream(call->localdesc, - SalProtoRtpSavp,SalAudio); - crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); + local_st_desc=sal_media_description_find_stream(call->localdesc,SalProtoRtpSavp,SalAudio); + crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); - if (crypto_idx >= 0) { - audio_stream_enable_srtp( - call->audiostream, - stream->crypto[0].algo, - local_st_desc->crypto[crypto_idx].master_key, - stream->crypto[0].master_key); - call->audiostream_encrypted=TRUE; - } else { - ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); - call->audiostream_encrypted=FALSE; - } + if (crypto_idx >= 0) { + audio_stream_enable_srtp( + call->audiostream, + stream->crypto[0].algo, + local_st_desc->crypto[crypto_idx].master_key, + stream->crypto[0].master_key); + call->audiostream_encrypted=TRUE; + } else { + ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); + call->audiostream_encrypted=FALSE; + } }else call->audiostream_encrypted=FALSE; if (call->params.in_conference){ /*transform the graph to connect it to the conference filter */ @@ -1939,7 +1934,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut params.zid_file=lc->zrtp_secrets_cache; audio_stream_enable_zrtp(call->audiostream,¶ms); - }else if (call->params.media_encryption==LinphoneMediaEncryptionSRTP){ + }else{ call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ? LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a378f8366..9f90061ec 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3329,6 +3329,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, linphone_call_set_state(call,LinphoneCallConnected,"Connected"); new_md=sal_call_get_final_media_description(call->op); linphone_core_update_streams(lc, call, new_md); + linphone_call_fix_call_parameters(call); if (new_md){ linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); }else call->media_pending=TRUE; From c2ca9f8c089b1b6ed8e7bc1f2bfa8d5a5defc524 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 7 Jan 2014 16:17:07 +0100 Subject: [PATCH 097/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 7451aeb8a..2307fb760 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7451aeb8a2ff0d709949b671a06a8ebd287c81b5 +Subproject commit 2307fb7601299bb4f5c74b0984385eaf60a86b3e From 4e82aa626b4b54adc12d493b9ac5adb08ce5c39c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 8 Jan 2014 12:06:36 +0100 Subject: [PATCH 098/439] better checking of incoming SDP, in order to avoid accept things we cannot support. --- coreapi/bellesip_sal/sal_op_call.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 024cf5313..e6c7229f4 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -352,21 +352,36 @@ static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_descriptio return 0; } +static int is_media_description_acceptable(SalMediaDescription *md){ + if (md->n_total_streams==0){ + ms_warning("Media description does not define any stream."); + return FALSE; + } + return TRUE; +} + static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { belle_sdp_session_description_t* sdp; + int err=0; SalReason reason; if (extract_sdp(BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) { if (sdp){ op->sdp_offering=FALSE; op->base.remote_media=sal_media_description_new(); sdp_to_media_description(sdp,op->base.remote_media); + /*make some sanity check about the SDP received*/ + if (!is_media_description_acceptable(op->base.remote_media)){ + err=-1; + reason=SalReasonNotAcceptable; + } belle_sip_object_unref(sdp); }else op->sdp_offering=TRUE; /*INVITE without SDP*/ - return 0; - }else{ + }else err=-1; + + if (err==-1){ sal_call_decline(op,reason,NULL); - return -1; } + return err; } static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { From e7edbcd8e803fd114548f6c3a6d9a33967a21607 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 8 Jan 2014 12:39:09 +0100 Subject: [PATCH 099/439] Add LinphoneTransportType enum documentation to the linphone_address group. --- coreapi/linphonecore.h | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7358159a9..14d4ff057 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -95,6 +95,7 @@ typedef struct _LCSipTransports{ /** * Enum describing transport type for LinphoneAddress. + * @ingroup linphone_address **/ enum _LinphoneTransportType{ LinphoneTransportUdp, From ac4348f800acfd1923624febd1055228b11a5b49 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 8 Jan 2014 17:42:39 +0100 Subject: [PATCH 100/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2307fb760..98c240f78 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2307fb7601299bb4f5c74b0984385eaf60a86b3e +Subproject commit 98c240f782a04db0cca32656635f5674eb933fd7 From ae6948ded397324c5c5194e0d91d2f27c8f96c55 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 9 Jan 2014 09:36:33 +0100 Subject: [PATCH 101/439] Moved belle sip object includes into private.h --- coreapi/contact_providers_priv.h | 2 +- coreapi/contactprovider.c | 3 +-- coreapi/linphonecore.h | 15 -------------- coreapi/private.h | 34 ++++++++++++++++++++++---------- gtk/main.c | 2 +- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/coreapi/contact_providers_priv.h b/coreapi/contact_providers_priv.h index 41b7bd327..b3d667df6 100644 --- a/coreapi/contact_providers_priv.h +++ b/coreapi/contact_providers_priv.h @@ -17,7 +17,7 @@ #ifndef CONTACT_PROVIDERS_PRIV_H #define CONTACT_PROVIDERS_PRIV_H -#include +#include "private.h" #include "linphonecore.h" /* Base for contact search and contact provider */ diff --git a/coreapi/contactprovider.c b/coreapi/contactprovider.c index cd40887b1..2ee037c78 100644 --- a/coreapi/contactprovider.c +++ b/coreapi/contactprovider.c @@ -59,7 +59,7 @@ int linphone_contact_search_compare(const void* a, const void* b) { return !(ra->id == rb->id); // return 0 if id is equal, 1 otherwise } -LinphoneContactSearch*linphone_ldap_contact_search_ref(void* obj) +LinphoneContactSearch*linphone_contact_search_ref(void* obj) { return LINPHONE_CONTACT_SEARCH(belle_sip_object_ref(obj)); } @@ -136,4 +136,3 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider) NULL, /* begin_search -> pure virtual */ NULL /* cancel_search -> pure virtual */ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END - diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 14d4ff057..b6532e2f2 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -33,9 +33,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" -#include -#include - #define LINPHONE_IPADDR_SIZE 64 #define LINPHONE_HOSTNAME_SIZE 128 @@ -2235,18 +2232,6 @@ 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); - -/** Belle Sip-based objects need unique ids - */ - -BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) -BELLE_SIP_TYPE_ID(LinphoneContactSearch), -BELLE_SIP_TYPE_ID(LinphoneContactProvider), -BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), -BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) -BELLE_SIP_DECLARE_TYPES_END - - /** Contact Providers */ diff --git a/coreapi/private.h b/coreapi/private.h index 3ce58499f..297535c34 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -34,6 +34,9 @@ extern "C" { #include "sal/sal.h" #include "sipsetup.h" +#include +#include + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -201,22 +204,22 @@ struct _LinphoneCall LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ int localdesc_changed; - + bool_t refer_pending; bool_t media_pending; bool_t audio_muted; bool_t camera_enabled; - + bool_t all_muted; /*this flag is set during early medias*/ bool_t playing_ringbacktone; bool_t owns_call_log; bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/ - + bool_t videostream_encrypted; bool_t audiostream_encrypted; bool_t auth_token_verified; bool_t defer_update; - + bool_t was_automatically_paused; bool_t ping_replied; bool_t record_active; @@ -381,9 +384,9 @@ LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); static const int linphone_proxy_config_magic=0x7979; -/*chat*/ +/*chat*/ void linphone_chat_message_destroy(LinphoneChatMessage* msg); -/**/ +/**/ struct _LinphoneProxyConfig { @@ -447,7 +450,7 @@ struct _LinphoneChatRoom{ }; - + struct _LinphoneFriend{ LinphoneAddress *uri; SalOp *insub; @@ -499,7 +502,7 @@ typedef struct rtp_config int nortp_timeout; int disable_upnp; bool_t rtp_no_xmit_on_audio_mute; - /* stop rtp xmit when audio muted */ + /* stop rtp xmit when audio muted */ bool_t audio_adaptive_jitt_comp_enabled; bool_t video_adaptive_jitt_comp_enabled; bool_t pad; @@ -645,12 +648,12 @@ struct _LinphoneCore bool_t apply_nat_settings; bool_t initial_subscribes_sent; bool_t bl_refresh; - + bool_t preview_finished; bool_t auto_net_state_mon; bool_t network_reachable; bool_t use_preview_window; - + time_t network_last_check; bool_t network_last_status; @@ -829,6 +832,17 @@ void linphone_free_xml_text_content(const char *text); xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +/** Belle Sip-based objects need unique ids + */ + +BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) +BELLE_SIP_TYPE_ID(LinphoneContactSearch), +BELLE_SIP_TYPE_ID(LinphoneContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), +BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) +BELLE_SIP_DECLARE_TYPES_END + + #ifdef __cplusplus } #endif diff --git a/gtk/main.c b/gtk/main.c index e47af7f3a..a7de9323b 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -847,7 +847,7 @@ static gboolean launch_contact_provider_search(void *userdata) ); if(search) - belle_sip_object_ref(search); + linphone_contact_search_ref(search); } return FALSE; } From 996a6a0d0f8c48f60bf33cfa6866af2ddd79f0d5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 9 Jan 2014 11:13:36 +0100 Subject: [PATCH 102/439] Add LinphoneTransportType typedef documentation to the linphone_address group. --- coreapi/linphonecore.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b6532e2f2..0ad6030da 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -102,6 +102,10 @@ enum _LinphoneTransportType{ }; /*this enum MUST be kept in sync with the SalTransport from sal.h*/ +/** + * Typedef for transport type enum. + * @ingroup linphone_address +**/ typedef enum _LinphoneTransportType LinphoneTransportType; /** From 71e654ad95ee593d802682f00391642d795900af Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 9 Jan 2014 19:00:17 +0100 Subject: [PATCH 103/439] change default dscp for video, because it is problematic on some routers to have two streams in parallel using the same dscp value. --- coreapi/linphonecore.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9f90061ec..f21f9af6e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6272,7 +6272,7 @@ 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); + return lp_config_get_int(lc->config,"rtp","video_dscp",0); } diff --git a/mediastreamer2 b/mediastreamer2 index 98c240f78..f17f45205 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 98c240f782a04db0cca32656635f5674eb933fd7 +Subproject commit f17f4520583843757237214b54ce8770886f7752 From d124b030e271261bcd62f9e77ad1aca6c00f5ee5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 10 Jan 2014 09:35:26 +0100 Subject: [PATCH 104/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f17f45205..0b5210a28 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f17f4520583843757237214b54ce8770886f7752 +Subproject commit 0b5210a283397b0deacf81bf0f80fc910cfc940b From 3e09aff60514d6946e6d74b9d8e42fd87ecc5ec4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 10 Jan 2014 11:26:39 +0100 Subject: [PATCH 105/439] Add unit test for RFC3994: is-composing notification. --- coreapi/chat.c | 15 +++++++++------ tester/liblinphone_tester.c | 1 + tester/liblinphone_tester.h | 4 +++- tester/marie_rc | 1 + tester/message_tester.c | 30 +++++++++++++++++++++++++++++- tester/pauline_rc | 1 + 6 files changed, 44 insertions(+), 8 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index ee6d66d3c..6dc8ae57a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -284,7 +284,7 @@ static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsin xmlXPathObjectPtr iscomposing_object; const char *state_str = NULL; const char *refresh_str = NULL; - int refresh_duration = COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT; + int refresh_duration = lp_config_get_int(cr->lc->config, "sip", "composing_remote_refresh_timeout", COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT); int i; LinphoneIsComposingState state = LinphoneIsComposingIdle; @@ -475,7 +475,8 @@ static char * linphone_chat_room_create_is_composing_xml(LinphoneChatRoom *cr) { } if ((err >= 0) && (cr->is_composing == LinphoneIsComposingActive)) { char refresh_str[4] = { 0 }; - snprintf(refresh_str, sizeof(refresh_str), "%u", COMPOSING_DEFAULT_REFRESH_TIMEOUT); + int refresh_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_refresh_timeout", COMPOSING_DEFAULT_REFRESH_TIMEOUT); + snprintf(refresh_str, sizeof(refresh_str), "%u", refresh_timeout); err = xmlTextWriterWriteElement(writer, (const xmlChar *)"refresh", (const xmlChar *)refresh_str); } if (err >= 0) { @@ -547,19 +548,21 @@ static int linphone_chat_room_refresh_composing(void *data, unsigned int revents } void linphone_chat_room_compose(LinphoneChatRoom *cr) { + int idle_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_idle_timeout", COMPOSING_DEFAULT_IDLE_TIMEOUT); + int refresh_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_refresh_timeout", COMPOSING_DEFAULT_REFRESH_TIMEOUT); if (cr->is_composing == LinphoneIsComposingIdle) { cr->is_composing = LinphoneIsComposingActive; linphone_chat_room_send_is_composing_notification(cr); if (!cr->composing_refresh_timer) { - cr->composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_refresh_composing, cr, COMPOSING_DEFAULT_REFRESH_TIMEOUT * 1000, "composing refresh timeout"); + cr->composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_refresh_composing, cr, refresh_timeout * 1000, "composing refresh timeout"); } else { - belle_sip_source_set_timeout(cr->composing_refresh_timer, COMPOSING_DEFAULT_REFRESH_TIMEOUT * 1000); + belle_sip_source_set_timeout(cr->composing_refresh_timer, refresh_timeout * 1000); } if (!cr->composing_idle_timer) { - cr->composing_idle_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_stop_composing, cr, COMPOSING_DEFAULT_IDLE_TIMEOUT * 1000, "composing idle timeout"); + cr->composing_idle_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_stop_composing, cr, idle_timeout * 1000, "composing idle timeout"); } } - belle_sip_source_set_timeout(cr->composing_idle_timer, COMPOSING_DEFAULT_IDLE_TIMEOUT * 1000); + belle_sip_source_set_timeout(cr->composing_idle_timer, idle_timeout * 1000); } /** diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index a5be38d65..dbbba9a46 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -191,6 +191,7 @@ 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.is_composing_received=is_composing_received; mgr->v_table.new_subscription_requested=new_subscription_requested; mgr->v_table.notify_presence_received=notify_presence_received; mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 2a8e33af0..93bde611a 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -117,7 +117,8 @@ typedef struct _stats { int number_of_LinphoneMessageInProgress; int number_of_LinphoneMessageDelivered; int number_of_LinphoneMessageNotDelivered; - + int number_of_LinphoneIsComposingActiveReceived; + int number_of_LinphoneIsComposingIdleReceived; int number_of_IframeDecoded; @@ -194,6 +195,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 is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); diff --git a/tester/marie_rc b/tester/marie_rc index d5b7d7c87..a8365e91e 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -5,6 +5,7 @@ sip_tls_port=5083 default_proxy=0 ping_with_options=0 register_only_when_network_is_up=0 +composing_idle_timeout=1 [auth_info_0] username=marie diff --git a/tester/message_tester.c b/tester/message_tester.c index c3001c226..ef0901c93 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -44,6 +44,15 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess } } +void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + stats *counters = get_stats(lc); + if (room->remote_is_composing == LinphoneIsComposingActive) { + counters->number_of_LinphoneIsComposingActiveReceived++; + } else { + counters->number_of_LinphoneIsComposingIdleReceived++; + } +} + void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { LinphoneCore* lc=(LinphoneCore*)ud; stats* counters = get_stats(lc); @@ -264,6 +273,24 @@ static void info_message_with_body(){ info_message_with_args(TRUE); } +static void is_composing_notification(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc, to); + int dummy = 0; + + ms_free(to); + linphone_chat_room_compose(chat_room); + wait_for_until(pauline->lc, marie->lc, &dummy, 1, 1500); /*just to sleep while iterating*/ + linphone_chat_room_send_message(chat_room, "Composing a message"); + CU_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneIsComposingActiveReceived, 1)); + CU_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneIsComposingIdleReceived, 2)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + test_t message_tests[] = { { "Text message", text_message }, { "Text message with privacy", text_message_with_privacy }, @@ -272,7 +299,8 @@ test_t message_tests[] = { { "Text message with send error", text_message_with_send_error }, { "Text message with external body", text_message_with_external_body }, { "Info message", info_message }, - { "Info message with body", info_message_with_body } + { "Info message with body", info_message_with_body }, + { "IsComposing notification", is_composing_notification } }; test_suite_t message_test_suite = { diff --git a/tester/pauline_rc b/tester/pauline_rc index 204486f66..4d01058fe 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -5,6 +5,7 @@ sip_tls_port=5073 default_proxy=0 ping_with_options=0 register_only_when_network_is_up=0 +composing_idle_timeout=1 [auth_info_0] username=pauline From 638671275f9a74e8bc2bf1ced7327e60e69c36a8 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 13 Jan 2014 16:36:51 +0100 Subject: [PATCH 106/439] Update ms2 for iOS orientation fix --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 0b5210a28..d1ef7469d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0b5210a283397b0deacf81bf0f80fc910cfc940b +Subproject commit d1ef7469d0d5baf73926fb3280141f225af5de60 From e756795dceda0b10b912edd872c08b30769f4cff Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 24 Dec 2013 21:57:49 +0100 Subject: [PATCH 107/439] RPM for redhat Linphone for redhat documentaton --- build/redhat/INSTALL | 13 +++++++++++ build/redhat/README | 51 ++++++++++++++++++++++++++++++++++++++++++++ gtk/ldap.ui | 2 +- linphone.spec.in | 2 +- 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 build/redhat/INSTALL create mode 100644 build/redhat/README diff --git a/build/redhat/INSTALL b/build/redhat/INSTALL new file mode 100644 index 000000000..0b43a5b51 --- /dev/null +++ b/build/redhat/INSTALL @@ -0,0 +1,13 @@ +INSTALL : + +Download and install the repo rpmforge : + http://repoforge.org/use/ + + $ sudo rpm -Uvh + +Download the linphone-release rpm + $ sudo rpm -Uvh + + $ sudo yum install linphone + + diff --git a/build/redhat/README b/build/redhat/README new file mode 100644 index 000000000..37e09e4d4 --- /dev/null +++ b/build/redhat/README @@ -0,0 +1,51 @@ +********************************** +* Compiling linphone on RedHat * +********************************** + +Download and install the repo rpmforge : + http://repoforge.org/use/ + + $ sudo rpm -Uhv + $ yum -y update + +- Install build time dependencies + $ sudo yum install libtool intltool + +- Install others dependencies + $ sudo yum install gtk2-devel + $ sudo yum install ffmpeg-devel + $ sudo yum install openldap-devel + +- Download and install packages + $ sudo rpm -Uhv ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-1.3.2-1.el6.x86_64.rpm + $ sudo rpm -Uvh ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-devel-1.3.2-1.el6.x86_64.rpm + $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-3.2-14.fc15.x86_64.rpm + $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-devel-3.2-14.fc15.x86_64.rpm + $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-tool-3.2-14.fc15.noarch.rpm + $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Fedora/i386/os/Packages/antlr3-java-3.2-14.fc15.noarch.rpm + +- Compile Belle-sip / oRTP / mediastreamer + $ ./autogen.sh + $ ./configure + $ make && make rpm + $ sudo rpm -Uvh + +- Compile Linphone + $ ./autogen.sh + $ ./configure + $ make && make rpm + + +-Create yum repo : + $ cd rpmbuild/RPMS/*arch*/ + $ createrepo . + + Create a file "linphone-release.repo" in /etc/yum.repos.d/ with : + + [linphone-release] + name = Linphone for redhat + baseurl = file/// *path to the new repo* + enabled = 1 + gpgcheck = 0 + + $ sudo yum install linphone diff --git a/gtk/ldap.ui b/gtk/ldap.ui index ba3bf7163..a5df241d1 100644 --- a/gtk/ldap.ui +++ b/gtk/ldap.ui @@ -1,6 +1,6 @@ - + False diff --git a/linphone.spec.in b/linphone.spec.in index e8e7b68a6..728ad5151 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 - --disable-tests --docdir=%{_docdir} --enable-ipv6 --enable-static --enable-external-mediastreamer --enable-external-ortp + --disable-tests --docdir=%{_docdir} --enable-ipv6 --enable-static --enable-external-mediastreamer --enable-external-ortp --enable-ldap %__make %{?_smp_mflags} From e4dcb70b9549b53821c10bd2c6ce85471064ce4f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 14 Jan 2014 09:07:12 +0100 Subject: [PATCH 108/439] Add generation of linphone_gitversion.h when using cmake. --- CMakeLists.txt | 1 + coreapi/CMakeLists.txt | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7af5d50ac..bc8718c0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ endif() include_directories( include/ coreapi/ + ${CMAKE_CURRENT_BINARY_DIR}/coreapi/ ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/libxml2/ ) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 74e80dfc0..ab83c3ce7 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -1,3 +1,38 @@ +find_program(GIT git) + +set(GIT_VERSION "unknown") +if(GIT) + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GIT} describe --always + OUTPUT_VARIABLE GIT_DESCRIBE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GIT} describe --abbrev=0 + OUTPUT_VARIABLE GIT_TAG + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GIT} rev-parse HEAD + OUTPUT_VARIABLE GIT_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(GIT_DESCRIBE) + set(GIT_VERSION ${GIT_DESCRIBE}) + else(GIT_DESCRIBE) + if(GIT_REVISION) + set(GIT_VERSION ${GIT_REVISION}) + endif(GIT_REVISION) + endif(GIT_DESCRIBE) +endif(GIT) +execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "#define LIBLINPHONE_GIT_VERSION \"${GIT_VERSION}\"" + OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/liblinphone_gitversion.h +) + set(SOURCE_FILES address.c authentication.c @@ -66,6 +101,7 @@ add_definitions( if(WIN32) add_definitions( -DWINDOW_NATIVE + /FIliblinphone_gitversion.h ) set(LIBS ws2_32) From 932837c3654eb73cbd0bb18b0d0f4321341a7ee8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 14 Jan 2014 09:07:43 +0100 Subject: [PATCH 109/439] Add option to enable video when compiling using cmake. --- CMakeLists.txt | 2 ++ coreapi/CMakeLists.txt | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc8718c0d..5dea97796 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 2.6) project(LINPHONE C) +option(LINPHONE_ENABLE_VIDEO "Build linphone with video support." ON) + if(NOT ORTP_ROOT_DIR) set(ORTP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/oRTP) endif() diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index ab83c3ce7..628695414 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -98,6 +98,10 @@ add_definitions( -DLINPHONE_PLUGINS_DIR="" ) +if(LINPHONE_ENABLE_VIDEO) + add_definitions(-DVIDEO_ENABLED) +endif(LINPHONE_ENABLE_VIDEO) + if(WIN32) add_definitions( -DWINDOW_NATIVE From 69407718da449015bc7886ab831ec5ca47e56f8f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 14 Jan 2014 09:09:54 +0100 Subject: [PATCH 110/439] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index d1ef7469d..ce1127bbf 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d1ef7469d0d5baf73926fb3280141f225af5de60 +Subproject commit ce1127bbf74a1bc1113a048195db3cf2ed49c946 diff --git a/oRTP b/oRTP index db393f57c..d42419299 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit db393f57ca12744f783b9e51776ea8897ba242d1 +Subproject commit d4241929983c8f0114f8de04dca6ecbc42b9607e From e3ab99b672b2653fabf7ecbd65b1a3dfd601d9e9 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 24 Dec 2013 23:39:06 +0100 Subject: [PATCH 111/439] Add git clone in the README --- build/redhat/README | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/redhat/README b/build/redhat/README index 37e09e4d4..7831df9c8 100644 --- a/build/redhat/README +++ b/build/redhat/README @@ -24,6 +24,12 @@ Download and install the repo rpmforge : $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-tool-3.2-14.fc15.noarch.rpm $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Fedora/i386/os/Packages/antlr3-java-3.2-14.fc15.noarch.rpm +- Git repository + + Belle-sip : git clone git://git.linphone.org/belle-sip.git + oRTP : git clone git://git.linphone.org/ortp.git + Mediastreamer : git clone git://git.linphone.org/mediastreamer2.git + - Compile Belle-sip / oRTP / mediastreamer $ ./autogen.sh $ ./configure From fd407a9f8d20dcafa4d6162ceed10dfad0d8f5ce Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 30 Dec 2013 17:07:10 +0100 Subject: [PATCH 112/439] Update LDAP provider to handle connection asynchronously. This is done through a thread which is launched to keep the UI responsive. Also configured the default server to "localhost" so that misconfiguration doesn't query example.com... --- coreapi/ldap/ldapprovider.c | 285 ++++++++++++++++++------------------ gtk/propertybox.c | 7 +- 2 files changed, 146 insertions(+), 146 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 6bdfa072a..8392ff8cb 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -18,6 +18,7 @@ #include "private.h" #include "lpconfig.h" #include "contact_providers_priv.h" +#include "mediastreamer2/mscommon.h" #include #ifdef BUILD_LDAP @@ -28,12 +29,6 @@ #define MAX_RUNNING_REQUESTS 10 #define FILTER_MAX_SIZE 512 -typedef enum { - ANONYMOUS, - PLAIN, - SASL -} LDAPAuthMethod; - struct LDAPFriendData { char* name; char* sip; @@ -49,16 +44,19 @@ struct _LinphoneLDAPContactProvider uint req_count; // bind transaction - int bind_msgid; - const char* auth_mechanism; bool_t connected; + ms_thread_t bind_thread; // config int use_tls; - LDAPAuthMethod auth_method; + const char* auth_method; const char* username; const char* password; const char* server; + const char* bind_dn; + + const char* sasl_authname; + const char* sasl_realm; const char* base_object; const char* sip_attr; @@ -70,6 +68,7 @@ struct _LinphoneLDAPContactProvider int timeout; int deref_aliases; int max_results; + }; struct _LinphoneLDAPContactSearch @@ -92,7 +91,6 @@ LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPConta { LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search); - struct timeval timeout = { cp->timeout, 0 }; linphone_contact_search_init(base, predicate, cb, cb_data); @@ -102,27 +100,6 @@ LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPConta snprintf(search->filter, FILTER_MAX_SIZE-1, cp->filter, predicate); search->filter[FILTER_MAX_SIZE-1] = 0; - ms_message("Calling ldap_search_ext with predicate '%s' on base %s", search->filter, cp->base_object); - - int ret = ldap_search_ext(search->ld, - cp->base_object, // base from which to start - LDAP_SCOPE_SUBTREE, - search->filter, // search predicate - cp->attributes, // which attributes to get - 0, // 0 = get attrs AND value, 1 = get attrs only - NULL, - NULL, - &timeout, // server timeout for the search - cp->max_results,// max result number - &search->msgid ); - - if( ret != LDAP_SUCCESS ){ - ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret)); - belle_sip_object_unref(search); - return NULL; - } else { - ms_message("LinphoneLDAPContactSearch created @%p : msgid %d", search, search->msgid); - } return search; } @@ -136,7 +113,6 @@ unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch return obj->found_count; } - static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj ) { //ms_message("~LinphoneLDAPContactSearch(%p)", obj); @@ -163,31 +139,7 @@ static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContact static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); static bool_t linphone_ldap_contact_provider_iterate(void *data); static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, unsigned flags, void *defaults, void *sasl_interact); - - -/* Authentication methods */ -struct AuthMethodDescription{ - LDAPAuthMethod method; - const char* description; -}; - -static struct AuthMethodDescription ldap_auth_method_description[] = { - {ANONYMOUS, "anonymous"}, - {PLAIN, "plain"}, - {SASL, "sasl"}, - {0, NULL} -}; - -static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* description ) -{ - struct AuthMethodDescription* desc = ldap_auth_method_description; - while( desc && desc->description ){ - if( strcmp(description, desc->description) == 0) - return desc->method; - desc++; - } - return ANONYMOUS; -} +static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req); static void linphone_ldap_contact_provider_destroy_request_cb(void *req) { @@ -210,38 +162,6 @@ static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* linphone_ldap_contact_provider_conf_destroy(obj); } -static int linphone_ldap_contact_provider_parse_bind_results( LinphoneLDAPContactProvider* obj, LDAPMessage* results ) -{ - int ret; - if( obj->auth_method == ANONYMOUS ) { - ms_message("ANONYMOUS BIND OK"); - ret = LDAP_SUCCESS; - } else { - ms_message("Advanced BIND follow-up"); - ret = ldap_sasl_interactive_bind(obj->ld, - NULL, // dn, should be NULL - "DIGEST-MD5", // TODO: use defined auth - NULL,NULL, // server and client controls - LDAP_SASL_QUIET, // never prompt, only use callback - linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed - obj, // private data - results, // result, to pass later on when a ldap_result() comes - &obj->auth_mechanism, - &obj->bind_msgid ); - if( ret != LDAP_SUCCESS){ - ms_error("ldap_parse_sasl_bind_result failed(%d)", ret); - } - } - - if( ret == LDAP_SUCCESS ){ - obj->connected = TRUE; - obj->bind_msgid = 0; - } - - return ret; - -} - static int linphone_ldap_contact_provider_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value) { if( strcmp(attr_name, obj->name_attr ) == 0 ){ @@ -335,7 +255,7 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon static bool_t linphone_ldap_contact_provider_iterate(void *data) { LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data); - if( obj->ld && ((obj->req_count > 0) || (obj->bind_msgid != 0) )){ + if( obj->ld && obj->connected && (obj->req_count > 0) ){ // never block struct timeval timeout = {0,0}; @@ -346,19 +266,14 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) switch( ret ){ case -1: { - ms_warning("Error in ldap_result : returned -1 (req_count %d, bind_msgid %d): %s", obj->req_count, obj->bind_msgid, ldap_err2string(errno)); + ms_warning("Error in ldap_result : returned -1 (req_count %d): %s", obj->req_count, ldap_err2string(errno)); break; } case 0: break; // nothing to do case LDAP_RES_BIND: { - ms_message("iterate: LDAP_RES_BIND"); - if( ldap_msgid( results ) != obj->bind_msgid ) { - ms_error("Bad msgid"); - } else { - linphone_ldap_contact_provider_parse_bind_results( obj, results ); - } + ms_error("iterate: unexpected LDAP_RES_BIND"); break; } case LDAP_RES_EXTENDED: @@ -389,6 +304,20 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) if( results ) ldap_msgfree(results); } + + if( obj->ld && obj->connected ){ + // check for pending searches + uint i; + + for( i=0; ireq_count; i++){ + LinphoneLDAPContactSearch* search = (LinphoneLDAPContactSearch*)ms_list_nth_data( obj->requests, i ); + if( search && search->msgid == 0){ + ms_message("Found pending search %p (for %s), launching...", search, search->filter); + linphone_ldap_contact_provider_perform_search(obj, search); + } + } + } + return TRUE; } @@ -410,6 +339,9 @@ static char* required_config_keys[] = { "auth_method", "username", "password", + "bind_dn", + "sasl_authname", + "sasl_realm", // search "base_object", @@ -455,24 +387,25 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide // clone new config into the dictionary obj->config = linphone_dictionary_ref(linphone_dictionary_clone(dict)); +#if 0 // until sasl auth is set up, force anonymous auth. + linphone_dictionary_set_string(obj->config, "auth_method", "ANONYMOUS"); +#endif + obj->use_tls = linphone_dictionary_get_int(obj->config, "use_tls", 0); obj->timeout = linphone_dictionary_get_int(obj->config, "timeout", 10); obj->deref_aliases = linphone_dictionary_get_int(obj->config, "deref_aliases", 0); obj->max_results = linphone_dictionary_get_int(obj->config, "max_results", 50); + obj->auth_method = linphone_dictionary_get_string(obj->config, "auth_method", "ANONYMOUS"); obj->username = linphone_dictionary_get_string(obj->config, "username", ""); obj->password = linphone_dictionary_get_string(obj->config, "password", ""); + obj->bind_dn = linphone_dictionary_get_string(obj->config, "bind_dn", ""); obj->base_object = linphone_dictionary_get_string(obj->config, "base_object", "dc=example,dc=com"); - obj->server = linphone_dictionary_get_string(obj->config, "server", "ldap://192.168.0.230:10389"); + obj->server = linphone_dictionary_get_string(obj->config, "server", "ldap://localhost"); obj->filter = linphone_dictionary_get_string(obj->config, "filter", "uid=*%s*"); obj->name_attr = linphone_dictionary_get_string(obj->config, "name_attribute", "givenName"); obj->sip_attr = linphone_dictionary_get_string(obj->config, "sip_attribute", "mobile"); - - /* - * Get authentication method - */ - obj->auth_method = linphone_ldap_contact_provider_auth_method( - linphone_dictionary_get_string(obj->config, "auth_method", "anonymous") - ); + obj->sasl_authname = linphone_dictionary_get_string(obj->config, "sasl_authname", ""); + obj->sasl_realm = linphone_dictionary_get_string(obj->config, "sasl_realm", ""); /* * parse the attributes list @@ -520,20 +453,23 @@ static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, switch( interact->id ) { case SASL_CB_GETREALM: - ms_message("* SASL_CB_GETREALM"); - dflt=NULL; + ms_message("* SASL_CB_GETREALM -> %s", obj->sasl_realm); + dflt = obj->sasl_realm; + break; + case SASL_CB_AUTHNAME: + ms_message("* SASL_CB_AUTHNAME -> %s", obj->sasl_authname); + dflt = obj->sasl_authname; break; case SASL_CB_USER: - case SASL_CB_AUTHNAME: - ms_message("* SASL_CB_AUTHNAME -> %s", obj->username); - dflt=obj->username; + ms_message("* SASL_CB_USER -> %s", obj->username); + dflt = obj->username; break; case SASL_CB_PASS: - ms_message("* SASL_CB_PASS -> %s", obj->password); - dflt=obj->password; + ms_message("* SASL_CB_PASS (hidden)"); + dflt = obj->password; break; default: - ms_message("my_sasl_interact asked for unknown %lx\n",interact->id); + ms_message("SASL interact asked for unknown id %lx\n",interact->id); } interact->result = (dflt && *dflt) ? dflt : (const char*)""; interact->len = strlen( (const char*)interact->result ); @@ -543,32 +479,42 @@ static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, return LDAP_SUCCESS; } -static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) +static void* ldap_bind_thread_func( void*arg) { + LinphoneLDAPContactProvider* obj = linphone_ldap_contact_provider_ref(arg); + const char* auth_mechanism = obj->auth_method; int ret; - const char* auth_mechanism = linphone_dictionary_get_string(obj->config, "auth_method", "anonymous"); - LDAPAuthMethod method = obj->auth_method; - if( method == ANONYMOUS ){ - // for anonymous authentication, use a simple sasl_bind - struct berval creds = {strlen(obj->password), ms_strdup(obj->password)}; - ret = ldap_sasl_bind(obj->ld, obj->base_object, NULL, &creds, NULL, NULL, &obj->bind_msgid); - if(creds.bv_val) ms_free(creds.bv_val); - } else { - ret = ldap_sasl_interactive_bind(obj->ld, - NULL, // dn, should be NULL - "SIMPLE",//"DIGEST-MD5", - NULL,NULL, // server and client controls - LDAP_SASL_QUIET, // never prompt, only use callback - linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed - obj, // private data - NULL, // result, to pass later on when a ldap_result() comes - &obj->auth_mechanism, - &obj->bind_msgid ); + if( (strcmp(auth_mechanism, "ANONYMOUS") == 0) || (strcmp(auth_mechanism, "SIMPLE") == 0) ) + { + struct berval passwd = { strlen(obj->password), ms_strdup(obj->password)}; + auth_mechanism = LDAP_SASL_SIMPLE; + ret = ldap_sasl_bind_s(obj->ld, + obj->bind_dn, + auth_mechanism, + &passwd, + NULL, + NULL, + NULL); + + ms_free(passwd.bv_val); } - if( ret == LDAP_SUCCESS || ret == LDAP_SASL_BIND_IN_PROGRESS ) { - if( ret == LDAP_SASL_BIND_IN_PROGRESS) ms_message("BIND_IN_PROGRESS"); - ms_message("LDAP bind request sent, auth: %s, msgid %x", obj->auth_mechanism?obj->auth_mechanism:"-", obj->bind_msgid); + else + { + + ms_message("LDAP interactive bind"); + ret = ldap_sasl_interactive_bind_s(obj->ld, + obj->bind_dn, + auth_mechanism, + NULL,NULL, + LDAP_SASL_QUIET, + linphone_ldap_contact_provider_bind_interact, + obj); + } + + if( ret == LDAP_SUCCESS ) { + ms_message("LDAP bind OK"); + obj->connected = 1; } else { int err; ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err); @@ -576,6 +522,15 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ret, err, ldap_err2string(err), auth_mechanism ); } + obj->bind_thread = 0; + linphone_ldap_contact_provider_unref(obj); + return (void*)0; +} + +static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) +{ + // perform the bind in an alternate thread, so that we don't stall the main loop + ms_thread_create(&obj->bind_thread, NULL, ldap_bind_thread_func, obj); return 0; } @@ -619,7 +574,7 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* } else { // prevents blocking calls to bind() when the server is invalid, but this is not working for now.. // see bug https://bugzilla.mozilla.org/show_bug.cgi?id=79509 - ldap_set_option( obj->ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON); + //ldap_set_option( obj->ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON); // register our hook into iterate so that LDAP can do its magic asynchronously. linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); @@ -678,22 +633,67 @@ static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContact return ret; } +static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req) +{ + int ret = -1; + struct timeval timeout = { obj->timeout, 0 }; + + if( req->msgid == 0 ){ + ms_message ( "Calling ldap_search_ext with predicate '%s' on base %s", req->filter, obj->base_object ); + ret = ldap_search_ext(obj->ld, + obj->base_object,// base from which to start + LDAP_SCOPE_SUBTREE, + req->filter, // search predicate + obj->attributes, // which attributes to get + 0, // 0 = get attrs AND value, 1 = get attrs only + NULL, + NULL, + &timeout, // server timeout for the search + obj->max_results,// max result number + &req->msgid ); + + if( ret != LDAP_SUCCESS ){ + ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret)); + } else { + ms_message("LinphoneLDAPContactSearch created @%p : msgid %d", req, req->msgid); + } + + } else { + ms_warning( "LDAP Search already performed for %s, msgid %d", req->filter, req->msgid); + } + return ret; +} + static LinphoneLDAPContactSearch* linphone_ldap_contact_provider_begin_search ( LinphoneLDAPContactProvider* obj, const char* predicate, ContactSearchCallback cb, void* cb_data ) { + bool_t connected = obj->connected; + // if we're not yet connected, bind - if( !obj->connected ) linphone_ldap_contact_provider_bind(obj); + if( !connected ) { + if( !obj->bind_thread ) linphone_ldap_contact_provider_bind(obj); + } - LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create ( obj, predicate, cb, cb_data ); + LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create( obj, predicate, cb, cb_data ); - if ( request != NULL ) { + if( connected ){ + int ret = linphone_ldap_contact_provider_perform_search(obj, request); ms_message ( "Created search %d for '%s', msgid %d, @%p", obj->req_count, predicate, request->msgid, request ); + if( ret != LDAP_SUCCESS ){ + belle_sip_object_unref(request); + request = NULL; + } + } else { + ms_message("Delayed search, wait for connection"); + } - obj->requests = ms_list_append ( obj->requests, request ); + if( request != NULL ) { + obj->requests = ms_list_append ( obj->requests, request ); obj->req_count++; } + return request; } @@ -708,13 +708,10 @@ static int linphone_ldap_contact_provider_marshal(LinphoneLDAPContactProvider* o error = belle_sip_snprintf(buff, buff_size, offset, "req_count:%d,\n", obj->req_count); if(error!= BELLE_SIP_OK) return error; - error = belle_sip_snprintf(buff, buff_size, offset, "bind_msgid:%d,\n", obj->bind_msgid); - if(error!= BELLE_SIP_OK) return error; - error = belle_sip_snprintf(buff, buff_size, offset, "CONFIG:\n" "tls: %d \n" - "auth: %d \n" + "auth: %s \n" "user: %s \n" "pass: %s \n" "server: %s \n" diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 57f3b0c4e..932f99aef 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -76,7 +76,7 @@ static void linphone_gtk_ldap_load_settings(GtkWidget* param) entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_server")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://example.com") ); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://localhost") ); entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_username")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"username", "") ); @@ -86,7 +86,7 @@ static void linphone_gtk_ldap_load_settings(GtkWidget* param) // TODO // GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"ldap_auth_method")); - // gtk_combo_box_set_active(entry, linphone_dictionary_get_string(ldap_conf,"auth_method", "anonymous") ); + // gtk_combo_box_set_active(entry, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS") ); entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_base_object")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"base_object", "dc=example,dc=com") ); @@ -113,6 +113,9 @@ static void linphone_gtk_ldap_load_settings(GtkWidget* param) spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_timeout")); gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"timeout", 10) ); + // TODO: add missing LDAP components + // TODO: move this to an external box + } void linphone_gtk_ldap_reset(GtkWidget *tabmgr) From 2bb42f89cc62ff05b177383fe662c06674dc8e88 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 30 Dec 2013 17:07:10 +0100 Subject: [PATCH 113/439] Update LDAP provider to handle connection asynchronously. This is done through a thread which is launched to keep the UI responsive. Also configured the default server to "localhost" so that misconfiguration doesn't query example.com... --- coreapi/ldap/ldapprovider.c | 285 ++++++++++++++++++------------------ gtk/propertybox.c | 7 +- 2 files changed, 146 insertions(+), 146 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 6bdfa072a..8392ff8cb 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -18,6 +18,7 @@ #include "private.h" #include "lpconfig.h" #include "contact_providers_priv.h" +#include "mediastreamer2/mscommon.h" #include #ifdef BUILD_LDAP @@ -28,12 +29,6 @@ #define MAX_RUNNING_REQUESTS 10 #define FILTER_MAX_SIZE 512 -typedef enum { - ANONYMOUS, - PLAIN, - SASL -} LDAPAuthMethod; - struct LDAPFriendData { char* name; char* sip; @@ -49,16 +44,19 @@ struct _LinphoneLDAPContactProvider uint req_count; // bind transaction - int bind_msgid; - const char* auth_mechanism; bool_t connected; + ms_thread_t bind_thread; // config int use_tls; - LDAPAuthMethod auth_method; + const char* auth_method; const char* username; const char* password; const char* server; + const char* bind_dn; + + const char* sasl_authname; + const char* sasl_realm; const char* base_object; const char* sip_attr; @@ -70,6 +68,7 @@ struct _LinphoneLDAPContactProvider int timeout; int deref_aliases; int max_results; + }; struct _LinphoneLDAPContactSearch @@ -92,7 +91,6 @@ LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPConta { LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch); LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search); - struct timeval timeout = { cp->timeout, 0 }; linphone_contact_search_init(base, predicate, cb, cb_data); @@ -102,27 +100,6 @@ LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPConta snprintf(search->filter, FILTER_MAX_SIZE-1, cp->filter, predicate); search->filter[FILTER_MAX_SIZE-1] = 0; - ms_message("Calling ldap_search_ext with predicate '%s' on base %s", search->filter, cp->base_object); - - int ret = ldap_search_ext(search->ld, - cp->base_object, // base from which to start - LDAP_SCOPE_SUBTREE, - search->filter, // search predicate - cp->attributes, // which attributes to get - 0, // 0 = get attrs AND value, 1 = get attrs only - NULL, - NULL, - &timeout, // server timeout for the search - cp->max_results,// max result number - &search->msgid ); - - if( ret != LDAP_SUCCESS ){ - ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret)); - belle_sip_object_unref(search); - return NULL; - } else { - ms_message("LinphoneLDAPContactSearch created @%p : msgid %d", search, search->msgid); - } return search; } @@ -136,7 +113,6 @@ unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch return obj->found_count; } - static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj ) { //ms_message("~LinphoneLDAPContactSearch(%p)", obj); @@ -163,31 +139,7 @@ static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContact static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj ); static bool_t linphone_ldap_contact_provider_iterate(void *data); static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, unsigned flags, void *defaults, void *sasl_interact); - - -/* Authentication methods */ -struct AuthMethodDescription{ - LDAPAuthMethod method; - const char* description; -}; - -static struct AuthMethodDescription ldap_auth_method_description[] = { - {ANONYMOUS, "anonymous"}, - {PLAIN, "plain"}, - {SASL, "sasl"}, - {0, NULL} -}; - -static LDAPAuthMethod linphone_ldap_contact_provider_auth_method( const char* description ) -{ - struct AuthMethodDescription* desc = ldap_auth_method_description; - while( desc && desc->description ){ - if( strcmp(description, desc->description) == 0) - return desc->method; - desc++; - } - return ANONYMOUS; -} +static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req); static void linphone_ldap_contact_provider_destroy_request_cb(void *req) { @@ -210,38 +162,6 @@ static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* linphone_ldap_contact_provider_conf_destroy(obj); } -static int linphone_ldap_contact_provider_parse_bind_results( LinphoneLDAPContactProvider* obj, LDAPMessage* results ) -{ - int ret; - if( obj->auth_method == ANONYMOUS ) { - ms_message("ANONYMOUS BIND OK"); - ret = LDAP_SUCCESS; - } else { - ms_message("Advanced BIND follow-up"); - ret = ldap_sasl_interactive_bind(obj->ld, - NULL, // dn, should be NULL - "DIGEST-MD5", // TODO: use defined auth - NULL,NULL, // server and client controls - LDAP_SASL_QUIET, // never prompt, only use callback - linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed - obj, // private data - results, // result, to pass later on when a ldap_result() comes - &obj->auth_mechanism, - &obj->bind_msgid ); - if( ret != LDAP_SUCCESS){ - ms_error("ldap_parse_sasl_bind_result failed(%d)", ret); - } - } - - if( ret == LDAP_SUCCESS ){ - obj->connected = TRUE; - obj->bind_msgid = 0; - } - - return ret; - -} - static int linphone_ldap_contact_provider_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value) { if( strcmp(attr_name, obj->name_attr ) == 0 ){ @@ -335,7 +255,7 @@ static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPCon static bool_t linphone_ldap_contact_provider_iterate(void *data) { LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data); - if( obj->ld && ((obj->req_count > 0) || (obj->bind_msgid != 0) )){ + if( obj->ld && obj->connected && (obj->req_count > 0) ){ // never block struct timeval timeout = {0,0}; @@ -346,19 +266,14 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) switch( ret ){ case -1: { - ms_warning("Error in ldap_result : returned -1 (req_count %d, bind_msgid %d): %s", obj->req_count, obj->bind_msgid, ldap_err2string(errno)); + ms_warning("Error in ldap_result : returned -1 (req_count %d): %s", obj->req_count, ldap_err2string(errno)); break; } case 0: break; // nothing to do case LDAP_RES_BIND: { - ms_message("iterate: LDAP_RES_BIND"); - if( ldap_msgid( results ) != obj->bind_msgid ) { - ms_error("Bad msgid"); - } else { - linphone_ldap_contact_provider_parse_bind_results( obj, results ); - } + ms_error("iterate: unexpected LDAP_RES_BIND"); break; } case LDAP_RES_EXTENDED: @@ -389,6 +304,20 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) if( results ) ldap_msgfree(results); } + + if( obj->ld && obj->connected ){ + // check for pending searches + uint i; + + for( i=0; ireq_count; i++){ + LinphoneLDAPContactSearch* search = (LinphoneLDAPContactSearch*)ms_list_nth_data( obj->requests, i ); + if( search && search->msgid == 0){ + ms_message("Found pending search %p (for %s), launching...", search, search->filter); + linphone_ldap_contact_provider_perform_search(obj, search); + } + } + } + return TRUE; } @@ -410,6 +339,9 @@ static char* required_config_keys[] = { "auth_method", "username", "password", + "bind_dn", + "sasl_authname", + "sasl_realm", // search "base_object", @@ -455,24 +387,25 @@ static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvide // clone new config into the dictionary obj->config = linphone_dictionary_ref(linphone_dictionary_clone(dict)); +#if 0 // until sasl auth is set up, force anonymous auth. + linphone_dictionary_set_string(obj->config, "auth_method", "ANONYMOUS"); +#endif + obj->use_tls = linphone_dictionary_get_int(obj->config, "use_tls", 0); obj->timeout = linphone_dictionary_get_int(obj->config, "timeout", 10); obj->deref_aliases = linphone_dictionary_get_int(obj->config, "deref_aliases", 0); obj->max_results = linphone_dictionary_get_int(obj->config, "max_results", 50); + obj->auth_method = linphone_dictionary_get_string(obj->config, "auth_method", "ANONYMOUS"); obj->username = linphone_dictionary_get_string(obj->config, "username", ""); obj->password = linphone_dictionary_get_string(obj->config, "password", ""); + obj->bind_dn = linphone_dictionary_get_string(obj->config, "bind_dn", ""); obj->base_object = linphone_dictionary_get_string(obj->config, "base_object", "dc=example,dc=com"); - obj->server = linphone_dictionary_get_string(obj->config, "server", "ldap://192.168.0.230:10389"); + obj->server = linphone_dictionary_get_string(obj->config, "server", "ldap://localhost"); obj->filter = linphone_dictionary_get_string(obj->config, "filter", "uid=*%s*"); obj->name_attr = linphone_dictionary_get_string(obj->config, "name_attribute", "givenName"); obj->sip_attr = linphone_dictionary_get_string(obj->config, "sip_attribute", "mobile"); - - /* - * Get authentication method - */ - obj->auth_method = linphone_ldap_contact_provider_auth_method( - linphone_dictionary_get_string(obj->config, "auth_method", "anonymous") - ); + obj->sasl_authname = linphone_dictionary_get_string(obj->config, "sasl_authname", ""); + obj->sasl_realm = linphone_dictionary_get_string(obj->config, "sasl_realm", ""); /* * parse the attributes list @@ -520,20 +453,23 @@ static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, switch( interact->id ) { case SASL_CB_GETREALM: - ms_message("* SASL_CB_GETREALM"); - dflt=NULL; + ms_message("* SASL_CB_GETREALM -> %s", obj->sasl_realm); + dflt = obj->sasl_realm; + break; + case SASL_CB_AUTHNAME: + ms_message("* SASL_CB_AUTHNAME -> %s", obj->sasl_authname); + dflt = obj->sasl_authname; break; case SASL_CB_USER: - case SASL_CB_AUTHNAME: - ms_message("* SASL_CB_AUTHNAME -> %s", obj->username); - dflt=obj->username; + ms_message("* SASL_CB_USER -> %s", obj->username); + dflt = obj->username; break; case SASL_CB_PASS: - ms_message("* SASL_CB_PASS -> %s", obj->password); - dflt=obj->password; + ms_message("* SASL_CB_PASS (hidden)"); + dflt = obj->password; break; default: - ms_message("my_sasl_interact asked for unknown %lx\n",interact->id); + ms_message("SASL interact asked for unknown id %lx\n",interact->id); } interact->result = (dflt && *dflt) ? dflt : (const char*)""; interact->len = strlen( (const char*)interact->result ); @@ -543,32 +479,42 @@ static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, return LDAP_SUCCESS; } -static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) +static void* ldap_bind_thread_func( void*arg) { + LinphoneLDAPContactProvider* obj = linphone_ldap_contact_provider_ref(arg); + const char* auth_mechanism = obj->auth_method; int ret; - const char* auth_mechanism = linphone_dictionary_get_string(obj->config, "auth_method", "anonymous"); - LDAPAuthMethod method = obj->auth_method; - if( method == ANONYMOUS ){ - // for anonymous authentication, use a simple sasl_bind - struct berval creds = {strlen(obj->password), ms_strdup(obj->password)}; - ret = ldap_sasl_bind(obj->ld, obj->base_object, NULL, &creds, NULL, NULL, &obj->bind_msgid); - if(creds.bv_val) ms_free(creds.bv_val); - } else { - ret = ldap_sasl_interactive_bind(obj->ld, - NULL, // dn, should be NULL - "SIMPLE",//"DIGEST-MD5", - NULL,NULL, // server and client controls - LDAP_SASL_QUIET, // never prompt, only use callback - linphone_ldap_contact_provider_bind_interact, // callback to call when info is needed - obj, // private data - NULL, // result, to pass later on when a ldap_result() comes - &obj->auth_mechanism, - &obj->bind_msgid ); + if( (strcmp(auth_mechanism, "ANONYMOUS") == 0) || (strcmp(auth_mechanism, "SIMPLE") == 0) ) + { + struct berval passwd = { strlen(obj->password), ms_strdup(obj->password)}; + auth_mechanism = LDAP_SASL_SIMPLE; + ret = ldap_sasl_bind_s(obj->ld, + obj->bind_dn, + auth_mechanism, + &passwd, + NULL, + NULL, + NULL); + + ms_free(passwd.bv_val); } - if( ret == LDAP_SUCCESS || ret == LDAP_SASL_BIND_IN_PROGRESS ) { - if( ret == LDAP_SASL_BIND_IN_PROGRESS) ms_message("BIND_IN_PROGRESS"); - ms_message("LDAP bind request sent, auth: %s, msgid %x", obj->auth_mechanism?obj->auth_mechanism:"-", obj->bind_msgid); + else + { + + ms_message("LDAP interactive bind"); + ret = ldap_sasl_interactive_bind_s(obj->ld, + obj->bind_dn, + auth_mechanism, + NULL,NULL, + LDAP_SASL_QUIET, + linphone_ldap_contact_provider_bind_interact, + obj); + } + + if( ret == LDAP_SUCCESS ) { + ms_message("LDAP bind OK"); + obj->connected = 1; } else { int err; ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err); @@ -576,6 +522,15 @@ static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ret, err, ldap_err2string(err), auth_mechanism ); } + obj->bind_thread = 0; + linphone_ldap_contact_provider_unref(obj); + return (void*)0; +} + +static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj ) +{ + // perform the bind in an alternate thread, so that we don't stall the main loop + ms_thread_create(&obj->bind_thread, NULL, ldap_bind_thread_func, obj); return 0; } @@ -619,7 +574,7 @@ LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* } else { // prevents blocking calls to bind() when the server is invalid, but this is not working for now.. // see bug https://bugzilla.mozilla.org/show_bug.cgi?id=79509 - ldap_set_option( obj->ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON); + //ldap_set_option( obj->ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON); // register our hook into iterate so that LDAP can do its magic asynchronously. linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj); @@ -678,22 +633,67 @@ static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContact return ret; } +static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req) +{ + int ret = -1; + struct timeval timeout = { obj->timeout, 0 }; + + if( req->msgid == 0 ){ + ms_message ( "Calling ldap_search_ext with predicate '%s' on base %s", req->filter, obj->base_object ); + ret = ldap_search_ext(obj->ld, + obj->base_object,// base from which to start + LDAP_SCOPE_SUBTREE, + req->filter, // search predicate + obj->attributes, // which attributes to get + 0, // 0 = get attrs AND value, 1 = get attrs only + NULL, + NULL, + &timeout, // server timeout for the search + obj->max_results,// max result number + &req->msgid ); + + if( ret != LDAP_SUCCESS ){ + ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret)); + } else { + ms_message("LinphoneLDAPContactSearch created @%p : msgid %d", req, req->msgid); + } + + } else { + ms_warning( "LDAP Search already performed for %s, msgid %d", req->filter, req->msgid); + } + return ret; +} + static LinphoneLDAPContactSearch* linphone_ldap_contact_provider_begin_search ( LinphoneLDAPContactProvider* obj, const char* predicate, ContactSearchCallback cb, void* cb_data ) { + bool_t connected = obj->connected; + // if we're not yet connected, bind - if( !obj->connected ) linphone_ldap_contact_provider_bind(obj); + if( !connected ) { + if( !obj->bind_thread ) linphone_ldap_contact_provider_bind(obj); + } - LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create ( obj, predicate, cb, cb_data ); + LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create( obj, predicate, cb, cb_data ); - if ( request != NULL ) { + if( connected ){ + int ret = linphone_ldap_contact_provider_perform_search(obj, request); ms_message ( "Created search %d for '%s', msgid %d, @%p", obj->req_count, predicate, request->msgid, request ); + if( ret != LDAP_SUCCESS ){ + belle_sip_object_unref(request); + request = NULL; + } + } else { + ms_message("Delayed search, wait for connection"); + } - obj->requests = ms_list_append ( obj->requests, request ); + if( request != NULL ) { + obj->requests = ms_list_append ( obj->requests, request ); obj->req_count++; } + return request; } @@ -708,13 +708,10 @@ static int linphone_ldap_contact_provider_marshal(LinphoneLDAPContactProvider* o error = belle_sip_snprintf(buff, buff_size, offset, "req_count:%d,\n", obj->req_count); if(error!= BELLE_SIP_OK) return error; - error = belle_sip_snprintf(buff, buff_size, offset, "bind_msgid:%d,\n", obj->bind_msgid); - if(error!= BELLE_SIP_OK) return error; - error = belle_sip_snprintf(buff, buff_size, offset, "CONFIG:\n" "tls: %d \n" - "auth: %d \n" + "auth: %s \n" "user: %s \n" "pass: %s \n" "server: %s \n" diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 46a750ead..4590e106c 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -76,7 +76,7 @@ static void linphone_gtk_ldap_load_settings(GtkWidget* param) entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_server")); - gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://example.com") ); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://localhost") ); entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_username")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"username", "") ); @@ -86,7 +86,7 @@ static void linphone_gtk_ldap_load_settings(GtkWidget* param) // TODO // GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"ldap_auth_method")); - // gtk_combo_box_set_active(entry, linphone_dictionary_get_string(ldap_conf,"auth_method", "anonymous") ); + // gtk_combo_box_set_active(entry, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS") ); entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_base_object")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"base_object", "dc=example,dc=com") ); @@ -113,6 +113,9 @@ static void linphone_gtk_ldap_load_settings(GtkWidget* param) spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_timeout")); gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"timeout", 10) ); + // TODO: add missing LDAP components + // TODO: move this to an external box + } void linphone_gtk_ldap_reset(GtkWidget *tabmgr) From fc09f54e166c84c847fac10155eb47a8f3fd5d15 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 31 Dec 2013 15:42:01 +0100 Subject: [PATCH 114/439] Moved LDAP configuration into a popup. --- coreapi/ldap/ldapprovider.c | 16 +- gtk/Makefile.am | 3 +- gtk/ldap.ui | 669 ++++++++++++++++++++++++++++++++++++ gtk/parameters.ui | 432 +++-------------------- gtk/propertybox.c | 148 +++++--- 5 files changed, 829 insertions(+), 439 deletions(-) create mode 100644 gtk/ldap.ui diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 8392ff8cb..93bd84787 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -288,7 +288,10 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) linphone_ldap_contact_provider_handle_search_result(obj, req, message ); message = ldap_next_message(obj->ld, message); } - if( req && ret == LDAP_RES_SEARCH_RESULT) linphone_ldap_contact_provider_cancel_search(LINPHONE_CONTACT_PROVIDER(obj), LINPHONE_CONTACT_SEARCH(req)); + if( req && ret == LDAP_RES_SEARCH_RESULT) + linphone_ldap_contact_provider_cancel_search( + LINPHONE_CONTACT_PROVIDER(obj), + LINPHONE_CONTACT_SEARCH(req)); break; } case LDAP_RES_MODIFY: @@ -312,8 +315,14 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) for( i=0; ireq_count; i++){ LinphoneLDAPContactSearch* search = (LinphoneLDAPContactSearch*)ms_list_nth_data( obj->requests, i ); if( search && search->msgid == 0){ + int ret; ms_message("Found pending search %p (for %s), launching...", search, search->filter); - linphone_ldap_contact_provider_perform_search(obj, search); + ret = linphone_ldap_contact_provider_perform_search(obj, search); + if( ret != LDAP_SUCCESS ){ + linphone_ldap_contact_provider_cancel_search( + LINPHONE_CONTACT_PROVIDER(obj), + LINPHONE_CONTACT_SEARCH(search)); + } } } } @@ -623,6 +632,7 @@ static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContact MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare_strong, req); if( list_entry ) { + ms_message("Delete search %p", req); ldap_cp->requests = ms_list_remove_link(ldap_cp->requests, list_entry); ldap_cp->req_count--; ret = 0; // return OK if we found it in the monitored requests @@ -639,7 +649,7 @@ static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactPro struct timeval timeout = { obj->timeout, 0 }; if( req->msgid == 0 ){ - ms_message ( "Calling ldap_search_ext with predicate '%s' on base %s", req->filter, obj->base_object ); + ms_message ( "Calling ldap_search_ext with predicate '%s' on base '%s', ld %p, attrs '%s', maxres = %d", req->filter, obj->base_object, obj->ld, obj->attributes[0], obj->max_results ); ret = ldap_search_ext(obj->ld, obj->base_object,// base from which to start LDAP_SCOPE_SUBTREE, diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 2f13d8b49..f9240eb02 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -11,7 +11,8 @@ UI_FILES= about.ui \ tunnel_config.ui \ waiting.ui \ dscp_settings.ui \ - call_statistics.ui + call_statistics.ui \ + ldap.ui PIXMAPS= \ stock_people.png diff --git a/gtk/ldap.ui b/gtk/ldap.ui new file mode 100644 index 000000000..ba3bf7163 --- /dev/null +++ b/gtk/ldap.ui @@ -0,0 +1,669 @@ + + + + + + False + LDAP Settings + + + True + False + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + 2 + + + True + False + 1 + Server address: + + + + + True + False + Authentication method: + + + 1 + 2 + + + + + True + False + Username: + + + 2 + 3 + + + + + True + False + Password: + + + 3 + 4 + + + + + Use TLS Connection + True + False + True + False + Not yet available + False + True + + + 1 + 2 + 4 + 5 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + + + + + True + False + liststore2 + 0 + + + + 0 + + + + + 1 + 2 + 1 + 2 + + + + + + + + + + + + True + False + <b>Connection</b> + True + + + + + True + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 3 + 2 + + + True + False + Bind DN + + + + + True + False + Authname + + + 1 + 2 + + + + + True + False + Realm + + + 2 + 3 + + + + + True + True + + False + False + True + True + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + + + + + True + False + <b>SASL</b> + True + + + + + True + True + 1 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + 2 + + + True + False + Base object: + + + + + True + False + Filter (%s for name): + + + 1 + 2 + + + + + True + False + Name Attribute: + + + 2 + 3 + + + + + True + False + SIP address attribute: + + + 3 + 4 + + + + + True + False + Attributes to query: + + + 4 + 5 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 1 + 2 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 2 + 3 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 3 + 4 + + + + + True + True + + True + False + False + True + True + + + 1 + 2 + 4 + 5 + + + + + + + + + True + False + <b>Search</b> + True + + + + + True + True + 2 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 3 + 2 + + + True + False + Timeout for search: + + + + + True + False + Max results: + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + timeout_adjustment + + + 1 + 2 + + + + + True + True + 3 + + True + False + False + True + True + result_adjustment + True + + + 1 + 2 + 1 + 2 + + + + + Follow Aliases + True + True + False + False + True + + + 1 + 2 + 2 + 3 + + + + + + + + + + + + True + False + <b>Miscellaneous</b> + True + + + + + True + True + 3 + + + + + True + False + 2 + + + + + + gtk-apply + True + True + True + False + True + + + + False + False + end + 1 + + + + + gtk-cancel + True + True + True + False + True + + + + False + False + end + 2 + + + + + False + True + 4 + + + + + + + + + + + + + ANONYMOUS + + + SIMPLE + + + DIGEST-MD5 + + + NTLM + + + + + 1 + 100 + 50 + 1 + 10 + + + 1 + 100 + 10 + 1 + 10 + + diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 5f42cf9c5..7705e1319 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -2470,13 +2470,15 @@ True False - 12 + 0 + 0 True False - 5 + 4 2 + True True @@ -2484,6 +2486,10 @@ 1 Server address: + + GTK_SHRINK + GTK_SHRINK + @@ -2494,6 +2500,7 @@ 1 2 + GTK_EXPAND | GTK_SHRINK @@ -2505,381 +2512,66 @@ 2 3 + GTK_SHRINK - - True - False - Password: - - - 3 - 4 - - - - - Use TLS Connection + + gtk-edit True True - False + True False - True - - - 1 - 2 - 4 - 5 - - - - - True - True - - False - False - True - True - - - 1 - 2 - - - - - True - True - - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - True - True - - True - False - False - True - True + True + 1 2 3 4 + GTK_SHRINK + GTK_SHRINK - + True False - liststore2 - 0 - 0 - 0 - - - - 0 - - + label + + + 1 + 2 + GTK_SHRINK + + + + + True + False + label 1 2 1 2 + GTK_SHRINK - - - - - - - True - False - <b>Connection</b> - True - - - - - True - True - 0 - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 5 - 2 - + True False - Base object: - - - - - True - False - Filter (%s for name): - - - 1 - 2 - - - - - True - False - Name Attribute: - - - 2 - 3 - - - - - True - False - SIP address attribute: - - - 3 - 4 - - - - - True - False - Attributes to query: - - - 4 - 5 - - - - - True - True - - False - False - True - True - - - 1 - 2 - - - - - True - True - - False - False - True - True - - - 1 - 2 - 1 - 2 - - - - - True - True - - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - True - True - - False - False - True - True - - - 1 - 2 - 3 - 4 - - - - - True - True - - False - False - True - True - - - 1 - 2 - 4 - 5 - - - - - - - - - True - False - <b>Search</b> - True - - - - - True - True - 1 - - - - - True - False - 0 - none - - - True - False - 12 - - - True - False - 3 - 2 - - - True - False - Timeout for search: - - - - - True - False - Max results: - - - 1 - 2 - - - - - True - True - - False - False - True - True - adjustment9 - - - 1 - 2 - - - - - True - True - 3 - - False - False - True - True - adjustment10 - True - - - 1 - 2 - 1 - 2 - - - - - Follow Aliases - True - True - False - False - True + label 1 2 2 3 + GTK_SHRINK @@ -2890,66 +2582,22 @@ - + True False - <b>Miscellaneous</b> + <b>LDAP Account setup</b> True - True + False True - 2 + 0 - - True - False - 2 - - - - - - Save - True - True - True - False - - - - False - False - end - 1 - - - - - Reset - True - True - True - False - - - - False - False - end - 2 - - - - - False - True - 3 - + diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 4590e106c..01134c073 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -60,125 +60,181 @@ static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); } +static void linphone_gtk_ldap_display( GtkWidget* param ) +{ + LpConfig* config = linphone_core_get_config(linphone_gtk_get_core()); + LinphoneDictionary* ldap_conf = lp_config_section_to_dict(config,"ldap"); + GtkLabel* label; + + ms_message("linphone_gtk_ldap_display"); + label= GTK_LABEL(linphone_gtk_get_widget(param,"ldap_server")); + gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"server", "ldap://localhost") ); + + label = GTK_LABEL(linphone_gtk_get_widget(param,"ldap_auth_method")); + gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS") ); + + label = GTK_LABEL(linphone_gtk_get_widget(param,"ldap_username")); + gtk_label_set_text(label, linphone_dictionary_get_string(ldap_conf,"username", "") ); +} + +static void linphone_gtk_ldap_set_authcombo( GtkComboBox* box, const char* authmethod ) +{ + GtkTreeModel* model = GTK_TREE_MODEL(gtk_combo_box_get_model(box)); + GtkTreeIter iter; + g_return_if_fail(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter) ); + + do{ + const char* value; + + gtk_tree_model_get(model,&iter,0,&value,-1); + if( value && strcmp(value, authmethod) == 0){ + gtk_combo_box_set_active_iter(box, &iter); + break; + } + + }while(gtk_tree_model_iter_next(model,&iter)); +} + static void linphone_gtk_ldap_load_settings(GtkWidget* param) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); LpConfig* config = linphone_core_get_config(linphone_gtk_get_core()); LinphoneDictionary* ldap_conf = lp_config_section_to_dict(config,"ldap"); GtkEntry* entry; GtkToggleButton* toggle; GtkSpinButton* spin; + GtkComboBox* cbox; - toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_use_tls")); + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(param,"ldap_use_tls")); gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"use_tls", 0) ); - - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_server")); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_server")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"server", "ldap://localhost") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_username")); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_username")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"username", "") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_password")); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_password")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"password", "") ); - // TODO - // GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"ldap_auth_method")); - // gtk_combo_box_set_active(entry, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS") ); + // SASL + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_bind_dn")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"bind_dn", "") ); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sasl_authname")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sasl_authname", "") ); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sasl_realm")); + gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sasl_realm", "") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_base_object")); + cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(param,"ldap_auth_method")); + linphone_gtk_ldap_set_authcombo(cbox, linphone_dictionary_get_string(ldap_conf,"auth_method", "ANONYMOUS")); + + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_base_object")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"base_object", "dc=example,dc=com") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_filter")); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_filter")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"filter", "uid=*%s*") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_name_attribute")); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_name_attribute")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"name_attribute", "cn") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_sip_attribute")); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_sip_attribute")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"sip_attribute", "mobile") ); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_attributes")); + entry = GTK_ENTRY(linphone_gtk_get_widget(param,"ldap_attributes")); gtk_entry_set_text(entry, linphone_dictionary_get_string(ldap_conf,"attributes", "cn,givenName,sn,mobile,homePhone") ); - toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_deref_aliases")); + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(param,"ldap_deref_aliases")); gtk_toggle_button_set_active(toggle, linphone_dictionary_get_int(ldap_conf,"deref_aliases", 0) ); - spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_max_results")); + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(param,"ldap_max_results")); gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"max_results", 50) ); - spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_timeout")); + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(param,"ldap_timeout")); gtk_spin_button_set_value(spin, linphone_dictionary_get_int(ldap_conf,"timeout", 10) ); - // TODO: add missing LDAP components - // TODO: move this to an external box - } -void linphone_gtk_ldap_reset(GtkWidget *tabmgr) + +void linphone_gtk_show_ldap_config(GtkWidget* button) { - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); - ms_message("RESET LDAP"); - linphone_gtk_ldap_load_settings(pb); + GtkWidget* param = gtk_widget_get_toplevel(button); + GtkWidget* ldap_config = linphone_gtk_create_window("ldap"); + linphone_gtk_ldap_load_settings(ldap_config); + + // to refresh parameters when the ldap config is destroyed + g_object_weak_ref(G_OBJECT(ldap_config), (GWeakNotify)linphone_gtk_ldap_display, (gpointer)param); + + gtk_widget_show(ldap_config); } -void linphone_gtk_ldap_save(GtkWidget *tabmgr) +void linphone_gtk_ldap_reset(GtkWidget *button) +{ + GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); + ms_message("RESET LDAP"); + gtk_widget_destroy(w); +} + +void linphone_gtk_ldap_save(GtkWidget *button) { LinphoneCore *lc = linphone_gtk_get_core(); LpConfig* conf = linphone_core_get_config(lc); LinphoneDictionary* dict = linphone_dictionary_new(); - GtkWidget *mw = linphone_gtk_get_main_window(); - GtkWidget *pb = (GtkWidget *) g_object_get_data(G_OBJECT(mw), "parameters"); + GtkWidget *ldap_widget = gtk_widget_get_toplevel(button); GtkEntry* entry; GtkToggleButton* toggle; GtkSpinButton* spin; ms_message("SAVE LDAP"); - toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_use_tls")); + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_use_tls")); linphone_dictionary_set_int(dict, "use_tls", gtk_toggle_button_get_active(toggle)); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_server")); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_server")); linphone_dictionary_set_string(dict, "server", gtk_entry_get_text(entry)); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_username")); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_username")); linphone_dictionary_set_string(dict, "username", gtk_entry_get_text(entry)); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_password")); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_password")); linphone_dictionary_set_string(dict, "password", gtk_entry_get_text(entry)); + // SASL + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_bind_dn")); + linphone_dictionary_set_string(dict, "bind_dn", gtk_entry_get_text(entry)); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sasl_authname")); + linphone_dictionary_set_string(dict, "sasl_authname", gtk_entry_get_text(entry)); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sasl_realm")); + linphone_dictionary_set_string(dict, "sasl_realm", gtk_entry_get_text(entry)); - GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"ldap_auth_method")); + + GtkComboBox* cbox = GTK_COMBO_BOX(linphone_gtk_get_widget(ldap_widget,"ldap_auth_method")); linphone_dictionary_set_string(dict, "auth_method", gtk_combo_box_get_active_text(cbox)); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_base_object")); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_base_object")); linphone_dictionary_set_string(dict, "base_object", gtk_entry_get_text(entry)); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_filter")); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_filter")); linphone_dictionary_set_string(dict, "filter", gtk_entry_get_text(entry)); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_name_attribute")); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_name_attribute")); linphone_dictionary_set_string(dict, "name_attribute", gtk_entry_get_text(entry)); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_sip_attribute")); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_sip_attribute")); linphone_dictionary_set_string(dict, "sip_attribute", gtk_entry_get_text(entry)); - entry = GTK_ENTRY(linphone_gtk_get_widget(pb,"ldap_attributes")); + entry = GTK_ENTRY(linphone_gtk_get_widget(ldap_widget,"ldap_attributes")); linphone_dictionary_set_string(dict, "attributes", gtk_entry_get_text(entry)); - toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"ldap_deref_aliases")); + toggle = GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_deref_aliases")); linphone_dictionary_set_int(dict, "deref_aliases", gtk_toggle_button_get_active(toggle)); - spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_max_results")); + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_max_results")); linphone_dictionary_set_int(dict, "max_results", gtk_spin_button_get_value(spin) ); - spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"ldap_timeout")); + spin = GTK_SPIN_BUTTON(linphone_gtk_get_widget(ldap_widget,"ldap_timeout")); linphone_dictionary_set_int(dict, "timeout", gtk_spin_button_get_value(spin) ); ms_message("Create LDAP from config"); @@ -186,6 +242,12 @@ void linphone_gtk_ldap_save(GtkWidget *tabmgr) linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(lc, dict) ); // save the config to linphonerc: lp_config_load_dict_to_section(conf, "ldap", dict); + + linphone_dictionary_unref(dict); + + // close widget + gtk_widget_destroy(ldap_widget); + } void linphone_gtk_fill_video_sizes(GtkWidget *combo){ @@ -1435,7 +1497,7 @@ void linphone_gtk_show_parameters(void){ /* LDAP CONFIG */ if( linphone_gtk_is_ldap_supported() ) { // if LDAP provider is available - linphone_gtk_ldap_load_settings(pb); + linphone_gtk_ldap_display(pb); } else { // hide the LDAP tab GtkNotebook* notebook = GTK_NOTEBOOK(linphone_gtk_get_widget(pb, "notebook1")); From f92e08b667d87d56188fc77c8719e0a246d45c9d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 2 Jan 2014 11:28:52 +0100 Subject: [PATCH 115/439] update README for mac --- README.macos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.macos b/README.macos index db01b4869..cc89ded86 100644 --- a/README.macos +++ b/README.macos @@ -30,7 +30,7 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ export CFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export OBJCFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" - $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" + $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5 -Wl,-headerpad_max_install_names" - Install libantlr3c (library used by belle-sip for parsing) $ git clone -b linphone git://git.linphone.org/antlr3.git From aeb09dfcedc3b568a0ba051100389ba659aa1d28 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 14 Jan 2014 13:06:12 +0100 Subject: [PATCH 116/439] fix README --- README | 9 ++--- README.zrtp | 94 ----------------------------------------------------- 2 files changed, 5 insertions(+), 98 deletions(-) delete mode 100644 README.zrtp diff --git a/README b/README index 8913f1205..1e3e0ced0 100644 --- a/README +++ b/README @@ -44,11 +44,12 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. $ sudo make install + Install zrtpcpp (optional), for unbreakable call encryption - $ sudo apt-get install cmake libssl-dev - $ git clone git://git.linphone.org/zrtpcpp.git - $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make + $ sudo apt-get install cmake + $ git clone https://github.com/wernerd/ZRTPCPP.git + $ cd ZRTPCPP + $ cmake -DCORE_LIB=true -DSDES=false . && make $ sudo make install - + If you get this error: "cc1plus: error: unrecognized command line option ‘-std=c++11’", edit CMakeLists.txt and replace c++11 by c++0x . - Compile linphone diff --git a/README.zrtp b/README.zrtp deleted file mode 100644 index c71c8d2d7..000000000 --- a/README.zrtp +++ /dev/null @@ -1,94 +0,0 @@ -ZRTP guide - -== Downloads == -- SRTP -http://sourceforge.net/projects/srtp/ -or "apt-get source libsrtp0" on Debian - -- ZRTP (libzrtpcpp-2.0) -http://www.gnutelephony.org/index.php/GNU_ZRTP - - -== Patch libzrtpcpp == -Index: src/ZIDFile.cpp -=================================================================== ---- src/ZIDFile.cpp (révision 754) -+++ src/ZIDFile.cpp (copie de travail) -@@ -78,10 +78,11 @@ - - // create save file name, rename and re-open - // if rename fails, just unlink old ZID file and create a brand new file -- // just a little inconnvenience for the user, need to verify new SAS -+ // just a little inconvenience for the user, need to verify new SAS - std::string fn = std::string(name) + std::string(".save"); - if (rename(name, fn.c_str()) < 0) { -- unlink(name); -+ // unlink(name); - createZIDFile(name); - return; - } -Index: src/libzrtpcpp/ZrtpCallback.h -=================================================================== ---- src/libzrtpcpp/ZrtpCallback.h (révision 754) -+++ src/libzrtpcpp/ZrtpCallback.h (copie de travail) -@@ -27,7 +27,7 @@ - - #include - #include --#include -+//#include - #include - - /** -Index: src/libzrtpcpp/ZIDRecord.h -=================================================================== ---- src/libzrtpcpp/ZIDRecord.h (révision 754) -+++ src/libzrtpcpp/ZIDRecord.h (copie de travail) -@@ -33,7 +33,7 @@ - - #include - #include --#include -+//#include - - #define IDENTIFIER_LEN 12 - #define RS_LENGTH 32 -Index: CMakeLists.txt -=================================================================== ---- CMakeLists.txt (révision 754) -+++ CMakeLists.txt (copie de travail) -@@ -124,11 +124,15 @@ - if(CMAKE_COMPILER_IS_GNUCXX) - add_definitions(-Wno-long-long -Wno-char-subscripts) - add_definitions(-Wall -ansi -pedantic) -+ add_definitions(-DNEW_STDCPP) - endif() - - add_subdirectory(src) --add_subdirectory(demo) - -+if (enable_ccrtp) -+ add_subdirectory(demo) -+endif() -+ - if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/package/) - MESSAGE(STATUS "package dir not found") - file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/package/) - - - -== Create simlinks or move folders == -submodules/external/srtp -> path_to_your_srtp_source -submodules/external/libzrtpcpp -> path_to_your_patched_zrtpcpp_source - - - -== Compilation for Android == -ndk-build BUILD_GPLV3_ZRTP=1 -j5 - - -== Compilation for Desktop version == -First ortp: ./autogen.sh && ./configure --enable-zrtp && make -j5 && sudo make install -Then mediastreamer2: ./autogen.sh && ./configure && make -j5 && sudo make install -Finally linphone: ./autogen.sh && ./configure --enable-external-ortp && make -j5 && sudo make install - From 9d315fd5ec029710faa5544bfb882c6967ce1e9a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 14 Jan 2014 13:28:09 +0100 Subject: [PATCH 117/439] update README for mac --- README.macos | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.macos b/README.macos index cc89ded86..41bea0e8a 100644 --- a/README.macos +++ b/README.macos @@ -58,8 +58,9 @@ The next pieces need to be compiled manually. To ensure compatibility with multi - Install zrtpcpp (optional), for unbreakable call encryption $ sudo port install cmake - $ git clone git://git.linphone.org/zrtpcpp.git - $ cd zrtpcpp && cmake -Denable-ccrtp=false . && make + $ git clone https://github.com/wernerd/ZRTPCPP.git + $ cd ZRTPCPP + $ cmake -DCORE_LIB=true -DSDES=false . && make $ sudo make install @@ -82,7 +83,7 @@ The next pieces need to be compiled manually. To ensure compatibility with multi Then or otherwise, do: - $ ./configure --prefix=/opt/local --with-readline=/opt/local --disable-x11 --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp --disable-strict && make + $ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure --prefix=/opt/local --with-readline=/opt/local --disable-x11 --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp --disable-strict && make Install to /opt/local From f0250b5a5fb9cb6a2bbf0432f7b4bb352189dafe Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 14 Jan 2014 14:47:47 +0100 Subject: [PATCH 118/439] make sure call media encryption call param is not 'fixed' in case of ZRTP --- coreapi/linphonecall.c | 5 +++-- tester/call_tester.c | 32 +++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index b386a3e33..0700577dc 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -688,7 +688,8 @@ static void linphone_call_set_terminated(LinphoneCall *call){ void linphone_call_fix_call_parameters(LinphoneCall *call){ call->params.has_video=call->current_params.has_video; - call->params.media_encryption=call->current_params.media_encryption; + if (call->params.media_encryption != LinphoneMediaEncryptionZRTP) /*in case of ZRTP call parameter are handle after zrtp negociation*/ + call->params.media_encryption=call->current_params.media_encryption; } const char *linphone_call_state_to_string(LinphoneCallState cs){ @@ -2770,4 +2771,4 @@ void linphone_call_set_contact_op(LinphoneCall* call) { sal_op_set_contact(call->op, contact); linphone_address_destroy(contact); } -} \ No newline at end of file +} diff --git a/tester/call_tester.c b/tester/call_tester.c index f65a4028d..347259bf4 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -916,19 +916,23 @@ static void simple_conference(void) { } -static void srtp_call(void) { +static void encrypted_call(LinphoneMediaEncryption mode) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { - linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); - linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + if (linphone_core_media_encryption_supported(marie->lc,mode)) { + linphone_core_set_media_encryption(marie->lc,mode); + linphone_core_set_media_encryption(pauline->lc,mode); 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); - + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),mode); + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),mode); + if (linphone_core_get_media_encryption(pauline->lc) == linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) { + /*check SAS*/ + CU_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) + ,linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))); + } /*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)); @@ -939,6 +943,16 @@ static void srtp_call(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } +static void srtp_call(LinphoneMediaEncryptionSRTP) { + encrypted_call(LinphoneMediaEncryptionSRTP); +} + +/* + * futur work +static void zrtp_call(LinphoneMediaEncryptionSRTP) { + encrypted_call(LinphoneMediaEncryptionZRTP); +}*/ + static void call_with_declined_srtp(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1007,6 +1021,9 @@ static void srtp_ice_call(void) { } + + + static void early_media_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_early_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -1476,6 +1493,7 @@ test_t call_tests[] = { { "Call paused resumed", call_paused_resumed }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, { "SRTP call", srtp_call }, + /*{ "ZRTP call",zrtp_call}, futur work*/ { "SRTP call with declined srtp", call_with_declined_srtp }, #ifdef VIDEO_ENABLED { "Simple video call",video_call}, From 0e8110fa2c6292e5fde30b341401df493e613391 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 15 Jan 2014 11:15:27 +0100 Subject: [PATCH 119/439] fix 3 way equality operation --- tester/call_tester.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 347259bf4..d8e94b5f3 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -928,7 +928,8 @@ static void encrypted_call(LinphoneMediaEncryption mode) { CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),mode); CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),mode); - if (linphone_core_get_media_encryption(pauline->lc) == linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) { + if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP + && linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) { /*check SAS*/ CU_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) ,linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))); From adb0356ade81a2480df7c8572de4fd7dd4f311d7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 15 Jan 2014 13:59:15 +0100 Subject: [PATCH 120/439] update README for macos --- README.macos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.macos b/README.macos index 41bea0e8a..a1f85b7f7 100644 --- a/README.macos +++ b/README.macos @@ -30,7 +30,7 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ export CFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export OBJCFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" - $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5 -Wl,-headerpad_max_install_names" + $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5 -Wl,-headerpad_max_install_names -Wl,-read_only_relocs -Wl,suppress" - Install libantlr3c (library used by belle-sip for parsing) $ git clone -b linphone git://git.linphone.org/antlr3.git From 60f7467c981e8e5be85a876f4cbd1079132f94df Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 15 Jan 2014 14:03:00 +0100 Subject: [PATCH 121/439] again --- README.macos | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.macos b/README.macos index a1f85b7f7..ebc79890e 100644 --- a/README.macos +++ b/README.macos @@ -32,6 +32,10 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5 -Wl,-headerpad_max_install_names -Wl,-read_only_relocs -Wl,suppress" +- (Optional) libvpx-1.2 has a bug on macos resulting in ugly video. It is recommended to upgrade it manually to 1.3 from source. + The libvpx build isn't able to produce dual architecture files. To workaround this, configure libvpx twice and use lipo to create a dual architecture + libvpx.a . + - Install libantlr3c (library used by belle-sip for parsing) $ git clone -b linphone git://git.linphone.org/antlr3.git $ cd antlr3/runtime/C From ec2838cc96b051f7d966d52ae45a646c09e383cf Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 15 Jan 2014 14:50:44 +0100 Subject: [PATCH 122/439] Free memory allocated by ortp_strdup() with ortp_free() instead of free() to prevent crashes on Windows. --- coreapi/lpconfig.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index d7a5d14f3..60e944882 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -79,13 +79,13 @@ LpSection *lp_section_new(const char *name){ void lp_item_destroy(void *pitem){ LpItem *item=(LpItem*)pitem; - free(item->key); - free(item->value); + ortp_free(item->key); + ortp_free(item->value); free(item); } void lp_section_destroy(LpSection *sec){ - free(sec->name); + ortp_free(sec->name); ms_list_for_each(sec->items,lp_item_destroy); ms_list_free(sec->items); free(sec); @@ -263,13 +263,13 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename){ } void lp_item_set_value(LpItem *item, const char *value){ - free(item->value); + ortp_free(item->value); item->value=ortp_strdup(value); } void lp_config_destroy(LpConfig *lpconfig){ - if (lpconfig->filename!=NULL) free(lpconfig->filename); + if (lpconfig->filename!=NULL) ortp_free(lpconfig->filename); ms_list_for_each(lpconfig->sections,(void (*)(void*))lp_section_destroy); ms_list_free(lpconfig->sections); free(lpconfig); From f7f18d1a4884b86b236657518e0ee080f6f2448f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 15 Jan 2014 17:28:16 +0100 Subject: [PATCH 123/439] update README for mac --- README.macos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.macos b/README.macos index ebc79890e..c967f90b1 100644 --- a/README.macos +++ b/README.macos @@ -64,7 +64,7 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ sudo port install cmake $ git clone https://github.com/wernerd/ZRTPCPP.git $ cd ZRTPCPP - $ cmake -DCORE_LIB=true -DSDES=false . && make + $ cmake -DCORE_LIB=true -DSDES=false -DCMAKE_INSTALL_NAME_DIR=/usr/local/lib . && make $ sudo make install From ce6c8a8949601f445e178f5c01b4a295d6e82f2d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 16 Jan 2014 09:54:20 +0100 Subject: [PATCH 124/439] update README.macos --- README.macos | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.macos b/README.macos index c967f90b1..35e03044d 100644 --- a/README.macos +++ b/README.macos @@ -64,8 +64,8 @@ The next pieces need to be compiled manually. To ensure compatibility with multi $ sudo port install cmake $ git clone https://github.com/wernerd/ZRTPCPP.git $ cd ZRTPCPP - $ cmake -DCORE_LIB=true -DSDES=false -DCMAKE_INSTALL_NAME_DIR=/usr/local/lib . && make - $ sudo make install + $ cmake -DCORE_LIB=true -DSDES=false CMAKE_INSTALL_NAME_DIR=/usr/local/lib/ -DCMAKE_C_FLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" -DCMAKE_CXX_FLAGS="-arch i386 -arch x86_64 --stdlib=libstdc++ -std=c++11 -lstdc++ -mmacosx-version-min=10.5" -DCMAKE_C_COMPILER=`xcrun --find clang` -DCMAKE_CXX_COMPILER=`xcrun --find clang` . +$ sudo make install - Install gsm codec (optional) From 959347055012a95bcb6f29c5ec61081f83e51c9f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Jan 2014 12:40:09 +0100 Subject: [PATCH 125/439] Install pdb file for Debug configuration on Windows when using cmake. --- coreapi/CMakeLists.txt | 16 +++++++++++++--- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 628695414..7dcefb8ca 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -135,6 +135,16 @@ endif() file(GLOB HEADER_FILES "*.h") install(FILES ${HEADER_FILES} - COMPONENT COMP_liblinphone - DESTINATION include/linphone - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + COMPONENT COMP_liblinphone + DESTINATION include/linphone + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ +) +if(WIN32) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/liblinphone.pdb + COMPONENT COMP_liblinphone + DESTINATION ${LIB_INSTALL_DIR} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE +) +endif() +endif(WIN32) diff --git a/mediastreamer2 b/mediastreamer2 index ce1127bbf..d9a04503f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ce1127bbf74a1bc1113a048195db3cf2ed49c946 +Subproject commit d9a04503fef1f05dd1659f1d68d25e30b952b243 diff --git a/oRTP b/oRTP index d42419299..8d5abfe21 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit d4241929983c8f0114f8de04dca6ecbc42b9607e +Subproject commit 8d5abfe216cb6ef851982dd8c9c313fc6b408624 From 6935d6cf3658a40a11e2da0ad45e360a914a1a3e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Jan 2014 17:04:52 +0100 Subject: [PATCH 126/439] Add check to prevent crashes when using a wrapper about liblinphone. If a wrapper holds a reference to a linphone call and the core is destroyed, the call can keep a reference to a core that no longer exists. This can cause some random crashes. --- coreapi/linphonecall.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 0700577dc..88e7c49e2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2086,12 +2086,15 @@ void linphone_call_stop_video_stream(LinphoneCall *call) { } void linphone_call_stop_media_streams(LinphoneCall *call){ - linphone_call_stop_audio_stream(call); - linphone_call_stop_video_stream(call); + if (call->audiostream || call->videostream) { + linphone_call_stop_audio_stream(call); + linphone_call_stop_video_stream(call); - if (call->core->msevq != NULL) { - ms_event_queue_skip(call->core->msevq); + if (call->core->msevq != NULL) { + ms_event_queue_skip(call->core->msevq); + } } + if (call->audio_profile){ rtp_profile_destroy(call->audio_profile); call->audio_profile=NULL; From b15fa27457d4b6d9c8d16ad73ce0378cd1c0b239 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 16 Jan 2014 17:52:16 +0100 Subject: [PATCH 127/439] Add video resolution in call stat --- gtk/call_statistics.ui | 48 +++++++++++++++++++++++++++++++++++++++++- gtk/incall_view.c | 15 +++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/gtk/call_statistics.ui b/gtk/call_statistics.ui index a647a8dca..2412d9793 100644 --- a/gtk/call_statistics.ui +++ b/gtk/call_statistics.ui @@ -59,7 +59,7 @@ True False - 7 + 9 2 True @@ -224,6 +224,52 @@ 7 + + + True + False + Video resolution received + + + 7 + 8 + + + + + True + False + + + 1 + 2 + 7 + 8 + + + + + True + False + Video resolution sent + + + 8 + 9 + + + + + True + False + + + 1 + 2 + 8 + 9 + + diff --git a/gtk/incall_view.c b/gtk/incall_view.c index da954a45b..8f96cfb27 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -256,14 +256,25 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ const char *audio_media_connectivity = _("Direct or through server"); const char *video_media_connectivity = _("Direct or through server"); gboolean has_video=linphone_call_params_video_enabled(linphone_call_get_current_params(call)); + MSVideoSize size_received = linphone_call_params_get_received_video_size(linphone_call_get_current_params(call)); + MSVideoSize size_sent = linphone_call_params_get_sent_video_size(linphone_call_get_current_params(call)); gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"), as->download_bandwidth,as->upload_bandwidth); gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp); g_free(tmp); - if (has_video) + if (has_video){ + gchar *size_r=g_strdup_printf(_("%ix%i"),size_received.width,size_received.height); + gchar *size_s=g_strdup_printf(_("%ix%i"),size_sent.width,size_sent.height); + gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_recv")),size_r); + gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_sent")),size_s); + tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),vs->download_bandwidth,vs->upload_bandwidth); - else tmp=NULL; + g_free(size_r); + g_free(size_s); + } else { + tmp=NULL; + } gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp); if (tmp) g_free(tmp); if(as->upnp_state != LinphoneUpnpStateNotAvailable && as->upnp_state != LinphoneUpnpStateIdle) { From 90f2d721708e7bdec5baabc0bd0677e37ae2b165 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Thu, 16 Jan 2014 18:10:16 +0100 Subject: [PATCH 128/439] Update ms2 Add new configuration in vp8 encoder --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d9a04503f..1ba518e96 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d9a04503fef1f05dd1659f1d68d25e30b952b243 +Subproject commit 1ba518e9647d1cf15c5e37173f7c3a246ea01440 From 5991559b4df85fa15f00c13ea26b822f325ee190 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 16 Jan 2014 18:13:55 +0100 Subject: [PATCH 129/439] Update oRTP submodule. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 8d5abfe21..7999f0509 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 8d5abfe216cb6ef851982dd8c9c313fc6b408624 +Subproject commit 7999f0509007658ea8c9b5edf096bf4dabf8ebd0 From 22b9c7791b9a47aa325f0583b928441fe4d5942c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 17 Jan 2014 11:02:57 +0100 Subject: [PATCH 130/439] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 1ba518e96..dc3efa305 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1ba518e9647d1cf15c5e37173f7c3a246ea01440 +Subproject commit dc3efa305148b83390bed160e93081c6f0612798 From 44a69aa44145c9797659079a4092f7013d90732b Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 17 Jan 2014 14:46:40 +0100 Subject: [PATCH 131/439] limit macosx version to 10.6 --- configure.ac | 9 +++++++++ mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d44cda018..218bc2784 100644 --- a/configure.ac +++ b/configure.ac @@ -313,6 +313,15 @@ if test "$gtk_ui" = "true" ; then fi fi +case "$target" in + #macosx 64 bits + x86_64-apple-darwin*) + LIBS="$LIBS -mmacosx-version-min=10.6" + CXXFLAGS="$CXXFLAGS -mmacosx-version-min=10.6" + CFLAGS="$CFLAGS -mmacosx-version-min=10.6" + ;; +esac + dnl os-specific problems not handled by existing macros. case "$host_os" in *freebsd*) diff --git a/mediastreamer2 b/mediastreamer2 index dc3efa305..50f1ed9aa 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit dc3efa305148b83390bed160e93081c6f0612798 +Subproject commit 50f1ed9aa4b852f4875687873e73d54fb92238c9 diff --git a/oRTP b/oRTP index 7999f0509..b46d5762b 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 7999f0509007658ea8c9b5edf096bf4dabf8ebd0 +Subproject commit b46d5762ba3ed86722651d8caf9711522f08ee0f From 562617a0f1ff5e166926041936272360b9f7213f Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Fri, 17 Jan 2014 15:03:57 +0100 Subject: [PATCH 132/439] Add static picture to linphone.bundle --- README | 2 +- build/macos/linphone.bundle | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README b/README index 1e3e0ced0..f4d3f6053 100644 --- a/README +++ b/README @@ -19,7 +19,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. - libavcodec (ffmpeg) - libswscale (part of ffmpeg too) for better scaling performance - libxv (x11 video extension) - - ligl1-mesa (OpenGL API -- GLX development files) + - libgl1-mesa (OpenGL API -- GLX development files) - libglew (OpenGL Extension Wrangler library) - libv4l (Video for linux) - libx11 (x11) diff --git a/build/macos/linphone.bundle b/build/macos/linphone.bundle index 780b73e1c..b7690a7f4 100644 --- a/build/macos/linphone.bundle +++ b/build/macos/linphone.bundle @@ -120,6 +120,11 @@ ${prefix:linphone}/share/pixmaps/linphone + + ${prefix:linphone}/share/images + + + From 5fe0448a6eab2eadf9b31c826ce0d6c46cbb0c45 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Mon, 20 Jan 2014 11:15:29 +0100 Subject: [PATCH 133/439] Ability to pass extended cflags. Useful to enable c++11 in extension code. --- build/android/Android.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index 9263f748f..8c64fae8a 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -190,9 +190,11 @@ LOCAL_CFLAGS += -DHAVE_ILBC=1 LOCAL_STATIC_LIBRARIES += libmsilbc endif -LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES) +LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES) LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS) LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES) +LOCAL_CFLAGS += $(LIBLINPHONE_EXTENDED_CFLAGS) + ifeq ($(BUILD_GPLV3_ZRTP),1) LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone From ef69fd041b9063b463f50dd0cd229a8f68ae4684 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 20 Jan 2014 13:03:12 +0100 Subject: [PATCH 134/439] MS2:disable builtin EC for Lenovo B6000-F --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 50f1ed9aa..968417441 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 50f1ed9aa4b852f4875687873e73d54fb92238c9 +Subproject commit 968417441911daf39d5c7dec18bc2a612add693f From 476e1006fbca10618fb775fc9446705231dae5c2 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 20 Jan 2014 14:44:43 +0100 Subject: [PATCH 135/439] Update ms2 submodule --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 968417441..b413084e4 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 968417441911daf39d5c7dec18bc2a612add693f +Subproject commit b413084e4e112f26b90154b4c801ec74256d42fa From 22e1427eb3b64d0eb9fcb77747425a4fa2b5eca7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 21 Jan 2014 12:17:00 +0100 Subject: [PATCH 136/439] fix automatic resuming of calls after failed failed transfer --- coreapi/bellesip_sal/sal_op_impl.c | 8 ++++++++ coreapi/callbacks.c | 32 +++++++++++++++++++----------- coreapi/linphonecore.c | 10 +++++----- coreapi/misc.c | 8 ++++++++ coreapi/private.h | 2 ++ include/sal/sal.h | 6 ++---- tester/call_tester.c | 6 ++++++ 7 files changed, 51 insertions(+), 21 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 51dec9b01..c62f7d441 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -638,3 +638,11 @@ bool_t sal_op_is_ipv6(SalOp *op){ return sal_address_is_ipv6((SalAddress*)contact); } +bool_t sal_op_is_idle(SalOp *op){ + if (op->dialog){ + return !belle_sip_dialog_request_pending(op->dialog); + } + return TRUE; +} + + diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index c2c382114..4f84da609 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -555,6 +555,23 @@ static void call_terminated(SalOp *op, const char *from){ linphone_call_set_state(call, LinphoneCallEnd,"Call ended"); } +static int resume_call_after_failed_transfer(LinphoneCall *call){ + ms_message("!!!!!!!!!!resume_call_after_failed_transfer"); + if (call->was_automatically_paused && call->state==LinphoneCallPausing) + return BELLE_SIP_CONTINUE; /*was still in pausing state*/ + + if (call->was_automatically_paused && call->state==LinphoneCallPaused){ + if (sal_op_is_idle(call->op)){ + linphone_core_resume_call(call->core,call); + }else { + ms_message("!!!!!!!!!!resume_call_after_failed_transfer, salop was busy"); + return BELLE_SIP_CONTINUE; + } + } + linphone_call_unref(call); + return BELLE_SIP_STOP; +} + static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); char *msg486=_("User is busy."); @@ -682,19 +699,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } if (referer){ - /* - * 1- resume call automatically if we had to pause it before to execute the transfer - * 2- notify other party of the transfer faillure - * This must be done at the end because transferer call can't be resumed until transfer-target call is changed to error state. - * This must be done in this order because if the notify transaction will prevent the resume transaction to take place. - * On the contrary, the notify transaction is queued and then executed after the resume completes. - **/ - if (linphone_call_get_state(referer)==LinphoneCallPaused && referer->was_automatically_paused){ - /*resume to the call that send us the refer automatically*/ - linphone_core_resume_call(lc,referer); - referer->was_automatically_paused=FALSE; - } + /*notify referer of the failure*/ linphone_core_notify_refer_state(lc,referer,call); + /*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/ + linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer"); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f21f9af6e..c7d68e601 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3594,10 +3594,8 @@ void linphone_core_preempt_sound_resources(LinphoneCore *lc){ * * @ingroup call_control **/ -int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) -{ +int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){ char temp[255]={0}; - LinphoneCall *call = the_call; const char *subject="Call resuming"; if(call->state!=LinphoneCallPaused ){ @@ -3606,18 +3604,20 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) } 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); + ms_warning("Cannot resume call %p because another call is locking the sound resources.",call); return -1; } linphone_core_preempt_sound_resources(lc); ms_message("Resuming call %p",call); } + call->was_automatically_paused=FALSE; + /* Stop playing music immediately. If remote side is a conference it prevents the participants to hear it while the 200OK comes back.*/ if (call->audiostream) audio_stream_play(call->audiostream, NULL); - linphone_call_make_local_media_description(lc,the_call); + linphone_call_make_local_media_description(lc,call); if (call->ice_session != NULL) { linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); } diff --git a/coreapi/misc.c b/coreapi/misc.c index e1d17e8be..5273ac35b 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1321,5 +1321,13 @@ const char *linphone_core_get_video_display_filter(LinphoneCore *lc){ return lp_config_get_string(lc->config,"video","displaytype",NULL); } +/** + * Queue a task into the main loop. The data pointer must remain valid until the task is completed. + * task_fun must return BELLE_SIP_STOP when job is finished. +**/ +void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description){ + belle_sip_source_t *s=sal_create_timer(lc->sal,task_fun,data, 20, task_description); + belle_sip_object_unref(s); +} diff --git a/coreapi/private.h b/coreapi/private.h index 297535c34..37546cd7b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -382,6 +382,8 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LinphoneCall * is_a_linphone_call(void *user_pointer); LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); +void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); + static const int linphone_proxy_config_magic=0x7979; /*chat*/ diff --git a/include/sal/sal.h b/include/sal/sal.h index 7e2ac70b9..ddf94a4e2 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -539,12 +539,8 @@ 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); @@ -562,6 +558,8 @@ void sal_op_set_service_route(SalOp *op,const SalAddress* service_route); void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled); bool_t sal_op_is_ipv6(SalOp *op); +/*returns TRUE if there is no pending request that may block a future one */ +bool_t sal_op_is_idle(SalOp *op); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); diff --git a/tester/call_tester.c b/tester/call_tester.c index d8e94b5f3..05a394423 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1257,6 +1257,12 @@ static void unattended_call_transfer_with_error(void) { /*the error must be reported back to marie*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000)); + /*and pauline should resume the call automatically*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallResuming,1,2000)); + + /*and call should be resumed*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); ms_list_free(lcs); From 27e1b112863020b8e4634ed404dd5fbc249aa713 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 21 Jan 2014 12:18:33 +0100 Subject: [PATCH 137/439] Simplify CMakeLists.txt. --- CMakeLists.txt | 49 ++++-------------------------------------- coreapi/CMakeLists.txt | 30 +++++++++++--------------- mediastreamer2 | 2 +- oRTP | 2 +- 4 files changed, 18 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dea97796..0d34e4890 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,31 +3,6 @@ project(LINPHONE C) option(LINPHONE_ENABLE_VIDEO "Build linphone with video support." ON) -if(NOT ORTP_ROOT_DIR) - set(ORTP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/oRTP) -endif() -if(NOT ORTP_INCLUDE_DIR) - set(ORTP_INCLUDE_DIR ${ORTP_ROOT_DIR}/include) -endif() -if(NOT MS2_ROOT_DIR) - set(MS2_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mediastreamer2) -endif() -if(NOT MS2_INCLUDE_DIR) - set(MS2_INCLUDE_DIR ${MS2_ROOT_DIR}/include) -endif() -if(NOT LIBXML2_ROOT_DIR) - set(LIBXML2_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libxml2) -endif() -if(NOT LIBXML2_INCLUDE_DIR) - set(LIBXML2_INCLUDE_DIR ${LIBXML2_ROOT_DIR}/include) -endif() -if(NOT BELLESIP_ROOT_DIR) - set(BELLESIP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../belle-sip) -endif() -if(NOT BELLESIP_INCLUDE_DIR) - set(BELLESIP_INCLUDE_DIR ${BELLESIP_ROOT_DIR}/include) -endif() - include_directories( include/ coreapi/ @@ -35,26 +10,10 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/libxml2/ ) -if(USE_INSTALLED_COMPONENTS) - include_directories( - ${CMAKE_INSTALL_PREFIX}/include - ${CMAKE_INSTALL_PREFIX}/include/libxml2 - ) -else() - include_directories( - ${ORTP_INCLUDE_DIR} - ${MS2_INCLUDE_DIR} - ${LIBXML2_INCLUDE_DIR} - ${BELLESIP_INCLUDE_DIR} - ) - if(WIN32) - include_directories(${ORTP_ROOT_DIR}/build/vsx/oRTP/oRTP/) - endif(WIN32) -endif() +include_directories( + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/include/libxml2 +) add_subdirectory(coreapi) add_subdirectory(share) - -if(INSTALL_COMPONENT_IN_POSTBUILD) - add_install_target(INSTALL_liblinphone COMP_liblinphone liblinphone) -endif() diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 7dcefb8ca..b608e4bfb 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -1,3 +1,9 @@ +find_library(LIBORTP NAMES ortp) +find_library(LIBMEDIASTREAMER_BASE NAMES mediastreamer_base) +find_library(LIBMEDIASTREAMER_VOIP NAMES mediastreamer_voip) +find_library(LIBBELLESIP NAMES bellesip) +find_library(LIBXML2 NAMES xml2) + find_program(GIT git) set(GIT_VERSION "unknown") @@ -91,7 +97,6 @@ add_definitions( -DIN_LINPHONE -DUSE_BELLESIP #-DTUNNEL_ENABLED - #-DVIDEO_ENABLED -DLINPHONE_PACKAGE_NAME="linphone" -DLINPHONE_VERSION="Devel" -DLIBLINPHONE_EXPORTS @@ -110,39 +115,28 @@ add_definitions( set(LIBS ws2_32) endif(WIN32) -set(LIBS ${LIBS} libortp libmediastreamer_base libmediastreamer_voip libbellesip libxml2) +set(LIBS ${LIBS} ${LIBORTP} ${LIBMEDIASTREAMER_BASE} ${LIBMEDIASTREAMER_VOIP} ${LIBBELLESIP} ${LIBXML2}) -add_library(liblinphone SHARED ${SOURCE_FILES}) -set_target_properties(liblinphone PROPERTIES VERSION 3.6.99 SOVERSION 5) +add_library(linphone SHARED ${SOURCE_FILES}) +set_target_properties(linphone PROPERTIES VERSION 3.6.99 SOVERSION 5) -target_link_libraries(liblinphone ${LIBS}) +target_link_libraries(linphone ${LIBS}) -install(TARGETS liblinphone - COMPONENT COMP_liblinphone +install(TARGETS linphone DESTINATION ${LIB_INSTALL_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -if(USE_INSTALLED_COMPONENTS) - add_dependencies(liblinphone - INSTALL_libortp - INSTALL_libmediastreamer2 - INSTALL_libbellesip - INSTALL_libxml2) -endif() - file(GLOB HEADER_FILES "*.h") install(FILES ${HEADER_FILES} - COMPONENT COMP_liblinphone DESTINATION include/linphone PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ ) if(WIN32) if(CMAKE_BUILD_TYPE STREQUAL "Debug") -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/liblinphone.pdb - COMPONENT COMP_liblinphone +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/linphone.pdb DESTINATION ${LIB_INSTALL_DIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) diff --git a/mediastreamer2 b/mediastreamer2 index b413084e4..e3e7cad4c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b413084e4e112f26b90154b4c801ec74256d42fa +Subproject commit e3e7cad4c0737982c100518acda3a95abf168038 diff --git a/oRTP b/oRTP index b46d5762b..aca5bcf65 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b46d5762ba3ed86722651d8caf9711522f08ee0f +Subproject commit aca5bcf65ee64806db02caadb4d4bc1c99a47775 From 9239a4e91ad6974c131a27c78e0b9f9c28094b9a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 21 Jan 2014 15:31:14 +0100 Subject: [PATCH 138/439] Fix linphonecore_destroy for windows phone --- coreapi/linphonecore.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c7d68e601..deb4a8161 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5470,24 +5470,25 @@ 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; - sal_iterate(lc->sal); + if (lc->network_reachable) { for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); - still_registered|=linphone_proxy_config_is_registered(cfg); + linphone_proxy_config_edit(cfg); /* to unregister */ } - ms_usleep(100000); + + ms_message("Unregistration started."); + + for (i=0;i<20&&still_registered;i++){ + still_registered=FALSE; + sal_iterate(lc->sal); + for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); + still_registered|=linphone_proxy_config_is_registered(cfg); + } + ms_usleep(100000); + } + if (i>=20) ms_warning("Cannot complete unregistration, giving up"); } - 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; From 82e74fe4ad93c40db9e9184fa116643c31e844bb Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 21 Jan 2014 17:14:49 +0100 Subject: [PATCH 139/439] Add linphone translation in the bundle --- build/macos/linphone.bundle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/macos/linphone.bundle b/build/macos/linphone.bundle index b7690a7f4..6b44ec400 100644 --- a/build/macos/linphone.bundle +++ b/build/macos/linphone.bundle @@ -101,6 +101,9 @@ want to copy in to the bundle. The "dest" attribute is optional, as usual. Bundler will find all translations of that library/program under the indicated directory and copy them.--> + + ${prefix}/share/locale + ${prefix}/share/locale From bc078d65d2c8f465eea9a0a37ee3b7db16efa0ae Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 22 Jan 2014 14:32:10 +0100 Subject: [PATCH 140/439] fix translations for mac os --- build/macos/linphone.bundle | 9 +++++++++ coreapi/private.h | 2 +- gtk/linphone.h | 4 ++-- gtk/main.c | 28 +++++++++++++++++++++------- oRTP | 2 +- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/build/macos/linphone.bundle b/build/macos/linphone.bundle index 6b44ec400..8008007ce 100644 --- a/build/macos/linphone.bundle +++ b/build/macos/linphone.bundle @@ -92,6 +92,9 @@ ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/engines/*.so + + ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/immodules/*.so + ${prefix}/lib/gio/modules/libgiognutls.so @@ -104,6 +107,12 @@ ${prefix}/share/locale + + ${prefix}/share/locale + + + ${prefix}/share/locale + ${prefix}/share/locale diff --git a/coreapi/private.h b/coreapi/private.h index 37546cd7b..f467c8202 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -66,7 +66,7 @@ extern "C" { #ifdef HAVE_GETTEXT #include #ifndef _ -#define _(String) gettext(String) +#define _(String) dgettext(GETTEXT_PACKAGE,String) #endif #else #ifndef _ diff --git a/gtk/linphone.h b/gtk/linphone.h index f9d918c51..024e6348a 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -33,7 +33,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef ENABLE_NLS # include # undef _ -# define _(String) gettext (String) +# define _(String) dgettext (GETTEXT_PACKAGE,String) #else # define _(String) (String) # define ngettext(singular,plural,number) ((number>1) ? (plural) : (singular) ) @@ -164,4 +164,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); \ No newline at end of file +gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); diff --git a/gtk/main.c b/gtk/main.c index a7de9323b..49ff8542b 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -361,6 +361,8 @@ GtkWidget *linphone_gtk_create_window(const char *window_name){ if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL; + gtk_builder_set_translation_domain(builder,GETTEXT_PACKAGE); + if (!gtk_builder_add_from_file (builder, path, &error)){ g_error("Couldn't load builder file: %s", error->message); g_error_free (error); @@ -387,6 +389,9 @@ GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_n object_ids[1]=NULL; if (get_ui_file(filename,path,sizeof(path))==-1) return NULL; + + gtk_builder_set_translation_domain(builder,GETTEXT_PACKAGE); + if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){ g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message); g_error_free (error); @@ -2070,9 +2075,6 @@ static gboolean on_block_termination(void){ #endif int main(int argc, char *argv[]){ -#ifdef ENABLE_NLS - void *p; -#endif char *config_file; const char *factory_config_file; const char *lang; @@ -2122,10 +2124,11 @@ int main(int argc, char *argv[]){ } #ifdef ENABLE_NLS - p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); - if (p==NULL) perror("bindtextdomain failed"); + bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); + setlocale(LC_ALL,""); + /*do not use textdomain(): this sets a global default domain. On Mac OS bundle, it breaks gtk translations (obscure bug somewhere)*/ + /*textdomain (GETTEXT_PACKAGE);*/ #else g_message("NLS disabled.\n"); #endif @@ -2159,7 +2162,18 @@ int main(int argc, char *argv[]){ g_error("Could not change directory to %s : %s",workingdir,strerror(errno)); } } - + +#if defined(__APPLE__) && defined(ENABLE_NLS) + /*workaround for bundles. GTK is unable to find translations in the bundle (obscure bug again). + So we help it:*/ + { + if (g_file_test(PACKAGE_LOCALE_DIR, G_FILE_TEST_IS_DIR)){ + bindtextdomain("gtk20",PACKAGE_LOCALE_DIR); + bindtextdomain("gdk-pixbuf",PACKAGE_LOCALE_DIR); + bindtextdomain("glib20",PACKAGE_LOCALE_DIR); + } + } +#endif /* Now, look for the factory configuration file, we do it this late since we want to have had time to change directory and to parse the options, in case we needed to access the working directory */ diff --git a/oRTP b/oRTP index aca5bcf65..b04994f1d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit aca5bcf65ee64806db02caadb4d4bc1c99a47775 +Subproject commit b04994f1d4f00d802fef64a665f0b77db4d98dee From 87d4f5f895c3f989d250614f0ced324502c900ea Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 22 Jan 2014 16:48:32 +0100 Subject: [PATCH 141/439] imlement java synchronization of LinphoneFriend with LinphoneCore --- coreapi/friend.c | 4 +++ coreapi/linphonecore_jni.cc | 10 +++++++ coreapi/linphonefriend.h | 5 ++++ .../org/linphone/core/LinphoneFriendImpl.java | 30 +++++++++++++++---- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/coreapi/friend.c b/coreapi/friend.c index c8417e22c..1a9705ea3 100644 --- a/coreapi/friend.c +++ b/coreapi/friend.c @@ -656,3 +656,7 @@ void linphone_core_write_friends_config(LinphoneCore* lc) linphone_friend_write_to_config_file(lc->config,NULL,i); /* set the end */ } +LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr){ + return fr->lc; +} + diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index a1f428b4a..5839f0c4b 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2222,6 +2222,16 @@ extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env ,jlong ptr) { return (jint)linphone_friend_get_status((LinphoneFriend*)ptr); } +extern "C" jobject Java_org_linphone_core_LinphoneFriendImpl_getCore(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + LinphoneCore *lc=linphone_friend_get_core((LinphoneFriend*)ptr); + if (lc!=NULL){ + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + return lcData->core; + } + return NULL; +} /* * Class: org_linphone_core_LinphoneFriendImpl diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 66fbcea8e..a38db19d0 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -392,6 +392,11 @@ LINPHONE_PUBLIC LinphoneFriend *linphone_core_find_friend(const LinphoneCore *lc */ LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key); + +/** + * Returns the LinphoneCore object managing this friend, if any. + */ +LINPHONE_PUBLIC LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr); /** * @} */ diff --git a/java/impl/org/linphone/core/LinphoneFriendImpl.java b/java/impl/org/linphone/core/LinphoneFriendImpl.java index 843170ce2..986f0a6b7 100644 --- a/java/impl/org/linphone/core/LinphoneFriendImpl.java +++ b/java/impl/org/linphone/core/LinphoneFriendImpl.java @@ -34,8 +34,9 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { private native void setPresenceModel(long nativePtr, long presencePtr); private native void edit(long nativePtr); private native void done(long nativePtr); - private native void delete(long ptr); + private native Object getCore(long ptr); + boolean ownPtr = false; protected LinphoneFriendImpl() { nativePtr = newLinphoneFriend(null); @@ -57,13 +58,17 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { return new LinphoneAddressImpl(getAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } public void setIncSubscribePolicy(SubscribePolicy policy) { - setIncSubscribePolicy(nativePtr,policy.mValue); + synchronized(getSyncObject()){ + setIncSubscribePolicy(nativePtr,policy.mValue); + } } public SubscribePolicy getIncSubscribePolicy() { return SubscribePolicy.fromInt(getIncSubscribePolicy(nativePtr)) ; } public void enableSubscribes(boolean enable) { - enableSubscribes(nativePtr, enable); + synchronized(getSyncObject()){ + enableSubscribes(nativePtr, enable); + } } public boolean isSubscribesEnabled() { return isSubscribesEnabled(nativePtr); @@ -75,12 +80,27 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { return (PresenceModel)getPresenceModel(nativePtr); } public void edit() { - edit(nativePtr); + synchronized(getSyncObject()){ + edit(nativePtr); + } } public void done() { - done(nativePtr); + synchronized(getSyncObject()){ + done(nativePtr); + } } public long getNativePtr() { return nativePtr; } + + /* + * Returns a java object to synchronize this friend with. + * Indeed some operation must be synchronized with the LinphoneCore object. + * If the friend is not associated with a LinphoneCore object, it returns itself in order to avoid writing code for case where no synchronization is necessary. + */ + private Object getSyncObject(){ + Object core=getCore(nativePtr); + if (core!=null) return core; + else return this; + } } From b5a6d4a2c63176a10c6f78990ecb2949f0ae2c4e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 22 Jan 2014 18:03:23 +0100 Subject: [PATCH 142/439] implement custom headers sending in 200Ok --- coreapi/bellesip_sal/sal_impl.h | 2 ++ coreapi/bellesip_sal/sal_op_call.c | 2 ++ coreapi/bellesip_sal/sal_op_impl.c | 2 +- coreapi/linphonecore.c | 1 + oRTP | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 4ae34095b..aa68feecc 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -159,4 +159,6 @@ SalReason sal_reason_to_sip_code(SalReason r); belle_sip_header_t * sal_make_supported_header(Sal *sal); +void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg); + #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index e6c7229f4..0aaec0512 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -709,6 +709,8 @@ int sal_call_accept(SalOp*h){ if ((contact_header=sal_op_create_contact(h))) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); } + + _sal_op_add_custom_headers(h, BELLE_SIP_MESSAGE(response)); handle_offer_answer_response(h,response); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index c62f7d441..70072d1f5 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -210,7 +210,7 @@ static void add_headers(belle_sip_header_t *h, belle_sip_message_t *msg){ belle_sip_message_add_header(msg,h); } -static void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){ +void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){ if (op->base.sent_custom_headers){ belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers; belle_sip_list_t *l=belle_sip_message_get_all_headers(ch); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index deb4a8161..f49ae5bc4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3303,6 +3303,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, if (md) call->params.has_video &= linphone_core_media_description_contains_video_stream(md); linphone_call_make_local_media_description(lc,call); sal_call_set_local_media_description(call->op,call->localdesc); + sal_op_set_sent_custom_header(call->op,params->custom_headers); } if (call->audiostream==NULL) diff --git a/oRTP b/oRTP index b04994f1d..d7b4d285d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b04994f1d4f00d802fef64a665f0b77db4d98dee +Subproject commit d7b4d285d8174566c16c600a9e61abed04cb8789 From a4ad87bcba9649b20f68c3583a88ba5fafb671e8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 22 Jan 2014 21:38:15 +0100 Subject: [PATCH 143/439] update ms2 for x11 windows clearing. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e3e7cad4c..184cca52e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e3e7cad4c0737982c100518acda3a95abf168038 +Subproject commit 184cca52e9816d02b1a3e94619e71547458481e8 From 8bf0387c35528ead879d1610e13e3a86fabc3669 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 23 Jan 2014 12:26:10 +0100 Subject: [PATCH 144/439] Added AndroidContext param to createlinphonecore (needed for opensles sound module for android) + updated ms2 --- build/android/Android.mk | 2 +- .../linphone/core/tutorials/TutorialBuddyStatus.java | 10 +++++----- .../org/linphone/core/tutorials/TutorialChatRoom.java | 2 +- .../linphone/core/tutorials/TutorialHelloWorld.java | 2 +- .../linphone/core/tutorials/TutorialRegistration.java | 2 +- java/common/org/linphone/core/LinphoneCoreFactory.java | 5 +++-- .../org/linphone/core/LinphoneCoreFactoryImpl.java | 7 +++++-- mediastreamer2 | 2 +- 8 files changed, 18 insertions(+), 14 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index 8c64fae8a..4f4e9954d 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -105,7 +105,7 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../externals/libxml2/include \ $(LOCAL_PATH)/../../externals/build/libxml2 -LOCAL_LDLIBS += -llog -ldl +LOCAL_LDLIBS += -llog -lOpenSLES -ldl LOCAL_STATIC_LIBRARIES := \ cpufeatures \ diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index c41ca2933..f7178b63c 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -20,24 +20,24 @@ package org.linphone.core.tutorials; import org.linphone.core.LinphoneAddress; import org.linphone.core.LinphoneCall; +import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCallStats; import org.linphone.core.LinphoneChatMessage; import org.linphone.core.LinphoneChatRoom; import org.linphone.core.LinphoneContent; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; +import org.linphone.core.LinphoneCore.GlobalState; +import org.linphone.core.LinphoneCore.RegistrationState; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; import org.linphone.core.LinphoneEvent; import org.linphone.core.LinphoneFriend; +import org.linphone.core.LinphoneFriend.SubscribePolicy; import org.linphone.core.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.OnlineStatus; -import org.linphone.core.LinphoneCall.State; -import org.linphone.core.LinphoneCore.GlobalState; -import org.linphone.core.LinphoneCore.RegistrationState; -import org.linphone.core.LinphoneFriend.SubscribePolicy; import org.linphone.core.PublishState; import org.linphone.core.SubscriptionState; @@ -140,7 +140,7 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { // First instantiate the core Linphone object given only a listener. // The listener will react to events in Linphone core. - LinphoneCore lc = lcFactory.createLinphoneCore(this); + LinphoneCore lc = lcFactory.createLinphoneCore(this, null); try { diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index 3278c990d..fc5e9dccc 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -116,7 +116,7 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa // First instantiate the core Linphone object given only a listener. // The listener will react to events in Linphone core. - LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this); + LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this, null); try { // Next step is to create a chat room diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index 763e18f12..e6761da97 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -113,7 +113,7 @@ public class TutorialHelloWorld implements LinphoneCoreListener { // First instantiate the core Linphone object given only a listener. // The listener will react to events in Linphone core. - LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this); + LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this, null); diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index 8384ed16e..7e6d8a002 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -118,7 +118,7 @@ public class TutorialRegistration implements LinphoneCoreListener { // First instantiate the core Linphone object given only a listener. // The listener will react to events in Linphone core. - LinphoneCore lc = lcFactory.createLinphoneCore(this); + LinphoneCore lc = lcFactory.createLinphoneCore(this, null); try { diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 95cfdeaf0..f394dbb4e 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -22,6 +22,7 @@ package org.linphone.core; + abstract public class LinphoneCoreFactory { private static String factoryName = "org.linphone.core.LinphoneCoreFactoryImpl"; @@ -65,8 +66,8 @@ abstract public class LinphoneCoreFactory { * */ 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; + abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata, Object context) throws LinphoneCoreException; + abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, Object context) throws LinphoneCoreException; /** diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index e526b47b5..521a3d6b1 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -21,6 +21,7 @@ package org.linphone.core; import java.io.File; import java.io.IOException; +import org.linphone.mediastream.MediastreamerAndroidContext; import org.linphone.mediastream.Version; import android.util.Log; @@ -94,9 +95,10 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { @Override public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, - String userConfig, String factoryConfig, Object userdata) + String userConfig, String factoryConfig, Object userdata, Object context) throws LinphoneCoreException { try { + MediastreamerAndroidContext.setContext(context); File user = userConfig == null ? null : new File(userConfig); File factory = factoryConfig == null ? null : new File(factoryConfig); return new LinphoneCoreImpl(listener, user, factory, userdata); @@ -106,8 +108,9 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } @Override - public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException { + public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, Object context) throws LinphoneCoreException { try { + MediastreamerAndroidContext.setContext(context); return new LinphoneCoreImpl(listener); } catch (IOException e) { throw new LinphoneCoreException("Cannot create LinphoneCore",e); diff --git a/mediastreamer2 b/mediastreamer2 index 184cca52e..1283fad5a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 184cca52e9816d02b1a3e94619e71547458481e8 +Subproject commit 1283fad5a14aaa14343206d96ba4133694349b3e From 3944782c244075ac1d29669183022a8ea5325e91 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 23 Jan 2014 16:58:39 +0100 Subject: [PATCH 145/439] updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 1283fad5a..0ec5df2bd 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1283fad5a14aaa14343206d96ba4133694349b3e +Subproject commit 0ec5df2bdb94433948fe6f56ee9f9b30b2466b0c From 4a3e43f2ff3fd8ed659cfc2c86e1cb1ee23b446f Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 23 Jan 2014 17:39:50 +0100 Subject: [PATCH 146/439] Use PKGCONFIG when possible for LDAP --- configure.ac | 40 ++++++++++++++++++++++++++++++---------- coreapi/Makefile.am | 5 +++-- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 218bc2784..fc5e5a52e 100644 --- a/configure.ac +++ b/configure.ac @@ -177,19 +177,39 @@ AC_ARG_ENABLE(ldap, ) if test "$enable_ldap" = "true"; then - AC_CHECK_LIB(sasl2, sasl_client_init , [foo=bar], - [AC_MSG_ERROR(You need SASL for LDAP support)] + PKG_CHECK_MODULES(LDAP, [openldap],[found_ldap=yes], [found_ldap=no]) + if test "$found_ldap" = "no"; then + AC_CHECK_LIB(ldap,ldap_initialize, [LDAP_LIBS="-lldap -llber"], + [AC_MSG_ERROR([You need libldap for LDAP support])] ) - - AC_CHECK_LIB(ldap,ldap_initialize, LDAP_LIBS="-lldap -llber -lsasl2", - [AC_MSG_ERROR(You need libldap for LDAP support)] - ) - - AC_CHECK_HEADERS(ldap.h) - AC_CHECK_HEADERS(sasl/sasl.h) + AC_CHECK_HEADERS(ldap.h, [foo=bar], [AC_MSG_ERROR( [ldap.h not found] ) ] ) + found_ldap=yes + fi + + PKG_CHECK_MODULES(SASL, [libsasl2],[found_sasl=yes],[found_sasl=no] ) + + if test "$found_sasl" = "no"; then + AC_CHECK_LIB(sasl2, sasl_client_init , [SASL_LIBS="-lsasl2"], + [AC_MSG_ERROR([You need SASL for LDAP support] ) ] + ) + AC_CHECK_HEADERS(sasl/sasl.h,foo=bar, [AC_MSG_ERROR([sasl/sasl.h not found])]) + found_sasl=yes + fi + + AC_SUBST(LDAP_CFLAGS) AC_SUBST(LDAP_LIBS) - AC_DEFINE(BUILD_LDAP,1,[Defined if LDAP build option enabled]) + + AC_SUBST(SASL_CFLAGS) + AC_SUBST(SASL_LIBS) + + if test "$found_ldap$found_sasl" = "yesyes"; then + AC_DEFINE(BUILD_LDAP,1,[Defined if LDAP build option enabled]) + else + AC_MSG_ERROR([Can't use LDAP due to previous errors]) + fi + fi + AM_CONDITIONAL(BUILD_LDAP, test x$enable_ldap != xfalse) dnl conditionnal build of console interface. diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 61d240464..9673552e5 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -109,7 +109,7 @@ liblinphone_la_LIBADD= \ $(LIBSOUP_LIBS) \ $(SQLITE3_LIBS) \ $(LIBXML2_LIBS) \ - $(LDAP_LIBS) + $(LDAP_LIBS) $(SASL_LIBS) if ENABLE_TESTS @@ -144,7 +144,8 @@ AM_CFLAGS=\ $(VIDEO_CFLAGS) \ $(TUNNEL_CFLAGS) \ $(SQLITE3_CFLAGS) \ - $(LIBXML2_CFLAGS) + $(LIBXML2_CFLAGS) \ + $(LDAP_CFLAGS) $(SASL_CFLAGS) if BUILD_WIZARD AM_CFLAGS+= -DBUILD_WIZARD From 2394027f9eaab48c16d579155be45bcfc753fe90 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 24 Jan 2014 10:44:26 +0100 Subject: [PATCH 147/439] Use standard unsigned int --- coreapi/ldap/ldapprovider.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/ldap/ldapprovider.c b/coreapi/ldap/ldapprovider.c index 93bd84787..f9a4add67 100644 --- a/coreapi/ldap/ldapprovider.c +++ b/coreapi/ldap/ldapprovider.c @@ -41,7 +41,7 @@ struct _LinphoneLDAPContactProvider LDAP* ld; MSList* requests; - uint req_count; + unsigned int req_count; // bind transaction bool_t connected; @@ -310,7 +310,7 @@ static bool_t linphone_ldap_contact_provider_iterate(void *data) if( obj->ld && obj->connected ){ // check for pending searches - uint i; + unsigned int i; for( i=0; ireq_count; i++){ LinphoneLDAPContactSearch* search = (LinphoneLDAPContactSearch*)ms_list_nth_data( obj->requests, i ); From 092375c98a2328526ef3a40706dd6084cd12e656 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 24 Jan 2014 11:09:52 +0100 Subject: [PATCH 148/439] SDP offer answer fix: declined streams must remain as inactive in future offers. --- coreapi/callbacks.c | 59 +++++++++++++++++++++---------------- coreapi/linphonecall.c | 66 +++++++++++++++++++++++++----------------- coreapi/linphonecore.c | 30 ++++++++++--------- coreapi/private.h | 5 ++-- coreapi/sal.c | 3 +- include/sal/sal.h | 2 +- 6 files changed, 96 insertions(+), 69 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 4f84da609..ab1f5a720 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -74,14 +74,28 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ SalMediaDescription *oldmd=call->resultdesc; + bool_t all_muted=FALSE; + bool_t send_ringbacktone=FALSE; linphone_core_stop_ringing(lc); - if (new_md!=NULL){ - sal_media_description_ref(new_md); - call->media_pending=FALSE; - }else{ - call->media_pending=TRUE; + if (!new_md) { + ms_error("linphone_core_update_streams() called with null media description"); + return; } + if (call->biggestdesc==NULL || new_md->n_total_streams>call->biggestdesc->n_total_streams){ + /*we have been offered and now are ready to proceed, or we added a new stream*/ + /*store the media description to remember the mapping of calls*/ + if (call->biggestdesc){ + sal_media_description_unref(call->biggestdesc); + call->biggestdesc=NULL; + } + if (sal_call_is_offerer(call->op)) + call->biggestdesc=sal_media_description_ref(call->localdesc); + else + call->biggestdesc=sal_media_description_ref(sal_call_get_remote_media_description(call->op)); + } + sal_media_description_ref(new_md); + call->expect_media_in_ack=FALSE; call->resultdesc=new_md; if ((call->audiostream && call->audiostream->ms.ticker) || (call->videostream && call->videostream->ms.ticker)){ /* we already started media: check if we really need to restart it*/ @@ -121,23 +135,18 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia linphone_call_init_media_streams (call); } - if (new_md) { - bool_t all_muted=FALSE; - bool_t send_ringbacktone=FALSE; - - if (call->audiostream==NULL){ - /*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/ - linphone_call_init_media_streams (call); - } - if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){ - send_ringbacktone=TRUE; - } - if (call->state==LinphoneCallIncomingEarlyMedia || - (call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){ - all_muted=TRUE; - } - linphone_call_start_media_streams(call,all_muted,send_ringbacktone); + if (call->audiostream==NULL){ + /*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/ + linphone_call_init_media_streams (call); } + if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){ + send_ringbacktone=TRUE; + } + if (call->state==LinphoneCallIncomingEarlyMedia || + (call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){ + all_muted=TRUE; + } + linphone_call_start_media_streams(call,all_muted,send_ringbacktone); if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){ linphone_core_play_named_tone(lc,LinphoneToneCallOnHold); } @@ -413,10 +422,10 @@ static void call_ack(SalOp *op){ ms_warning("No call to be ACK'd"); return ; } - if (call->media_pending){ + if (call->expect_media_in_ack){ SalMediaDescription *md=sal_call_get_final_media_description(op); if (md && !sal_media_description_empty(md)){ - linphone_core_update_streams (lc,call,md); + linphone_core_update_streams(lc,call,md); linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)"); }else{ /*send a bye*/ @@ -430,7 +439,7 @@ static void call_ack(SalOp *op){ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ SalMediaDescription *md; SalMediaDescription *rmd=sal_call_get_remote_media_description(call->op); - if ((rmd!=NULL) && (call->ice_session!=NULL)) { + if (rmd!=NULL && call->ice_session!=NULL) { linphone_core_update_ice_from_remote_media_description(call,rmd); linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session); } @@ -492,7 +501,7 @@ static void call_updating(SalOp *op){ if (rmd==NULL){ /* case of a reINVITE without SDP */ call_accept_update(lc,call); - call->media_pending=TRUE; + call->expect_media_in_ack=TRUE; return; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 88e7c49e2..e7a1390cc 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -229,6 +229,35 @@ static void update_media_description_from_stun(SalMediaDescription *md, const St } } +static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ + LinphoneCore *lc=call->core; + int i; + SalMediaDescription *old_md=call->localdesc; + bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); + + for(i=0; in_active_streams; i++) { + if (md->streams[i].proto == SalProtoRtpSavp) { + if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ + int j; + ms_message("Keeping same crypto keys."); + for(j=0;jstreams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo)); + } + }else{ + md->streams[i].crypto[0].tag = 1; + md->streams[i].crypto[0].algo = AES_128_SHA1_80; + if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key, SAL_SRTP_KEY_SIZE)) + md->streams[i].crypto[0].algo = 0; + md->streams[i].crypto[1].tag = 2; + md->streams[i].crypto[1].algo = AES_128_SHA1_32; + if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key, SAL_SRTP_KEY_SIZE)) + md->streams[i].crypto[1].algo = 0; + md->streams[i].crypto[2].algo = 0; + } + } + } +} + void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ MSList *l; PayloadType *pt; @@ -237,7 +266,6 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * const char *me; SalMediaDescription *md=sal_media_description_new(); LinphoneAddress *addr; - bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); char* local_ip=call->localip; linphone_core_adapt_to_network(lc,call->ping_time,&call->params); @@ -250,8 +278,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * 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; + md->n_total_streams=(call->biggestdesc ? call->biggestdesc->n_total_streams : 1); + strncpy(md->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); @@ -260,6 +288,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * else md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ + md->n_active_streams=1; 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; @@ -292,34 +321,15 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * for (i = md->n_active_streams; i < md->n_total_streams; i++) { md->streams[i].rtp_port = 0; md->streams[i].rtcp_port = 0; - md->streams[i].proto = SalProtoRtpAvp; - md->streams[i].type = old_md->streams[i].type; + md->streams[i].proto = call->biggestdesc->streams[i].proto; + md->streams[i].type = call->biggestdesc->streams[i].type; md->streams[i].dir = SalStreamInactive; l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1); md->streams[i].payloads = l; } - for(i=0; in_active_streams; i++) { - if (md->streams[i].proto == SalProtoRtpSavp) { - if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ - int j; - ms_message("Keeping same crypto keys."); - for(j=0;jstreams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo)); - } - }else{ - md->streams[i].crypto[0].tag = 1; - md->streams[i].crypto[0].algo = AES_128_SHA1_80; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key, SAL_SRTP_KEY_SIZE)) - md->streams[i].crypto[0].algo = 0; - md->streams[i].crypto[1].tag = 2; - md->streams[i].crypto[1].algo = AES_128_SHA1_32; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key, SAL_SRTP_KEY_SIZE)) - md->streams[i].crypto[1].algo = 0; - md->streams[i].crypto[2].algo = 0; - } - } - } + setup_encryption_keys(call,md); + update_media_description_from_stun(md,&call->ac,&call->vc); if (call->ice_session != NULL) { linphone_core_update_local_media_description_from_ice(md, call->ice_session); @@ -817,6 +827,10 @@ static void linphone_call_destroy(LinphoneCall *obj) sal_op_release(obj->op); obj->op=NULL; } + if (obj->biggestdesc!=NULL){ + sal_media_description_unref(obj->biggestdesc); + obj->biggestdesc=NULL; + } if (obj->resultdesc!=NULL) { sal_media_description_unref(obj->resultdesc); obj->resultdesc=NULL; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f49ae5bc4..522c93f23 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2558,20 +2558,22 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ 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); - } real_url=linphone_address_as_string(call->log->to); from=linphone_address_as_string(call->log->from); - err=sal_call(call->op,from,real_url); - call->log->call_id=ms_strdup(sal_op_get_call_id(call->op)); /*must be known at that time*/ - - if (lc->sip_conf.sdp_200_ack){ - call->media_pending=TRUE; + + if (!lc->sip_conf.sdp_200_ack){ + /*we are offering, set local media description before sending the call*/ sal_call_set_local_media_description(call->op,call->localdesc); } + err=sal_call(call->op,from,real_url); + if (lc->sip_conf.sdp_200_ack){ + /*we are NOT offering, set local media description after sending the call so that we are ready to + process the remote offer when it will arrive*/ + sal_call_set_local_media_description(call->op,call->localdesc); + } + + call->log->call_id=ms_strdup(sal_op_get_call_id(call->op)); /*must be known at that time*/ + barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,barmsg); @@ -2954,7 +2956,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (propose_early_media || ringback_tone!=NULL){ linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); md=sal_call_get_final_media_description(call->op); - linphone_core_update_streams(lc,call,md); + if (md) linphone_core_update_streams(lc,call,md); } if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ linphone_core_accept_call(lc,call); @@ -3329,11 +3331,11 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, lc->current_call=call; linphone_call_set_state(call,LinphoneCallConnected,"Connected"); new_md=sal_call_get_final_media_description(call->op); - linphone_core_update_streams(lc, call, new_md); - linphone_call_fix_call_parameters(call); if (new_md){ + linphone_core_update_streams(lc, call, new_md); + linphone_call_fix_call_parameters(call); linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); - }else call->media_pending=TRUE; + }else call->expect_media_in_ack=TRUE; ms_message("call answered."); return 0; diff --git a/coreapi/private.h b/coreapi/private.h index f467c8202..32d3553a0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -158,9 +158,10 @@ struct _LinphoneCall int magic; /*used to distinguish from proxy config*/ struct _LinphoneCore *core; int af; /*the address family to prefer for RTP path, guessed from signaling path*/ + LinphoneCallDir dir; + SalMediaDescription *biggestdesc; /*media description with all already proposed streams, used to remember the mapping of streams*/ SalMediaDescription *localdesc; SalMediaDescription *resultdesc; - LinphoneCallDir dir; struct _RtpProfile *audio_profile; struct _RtpProfile *video_profile; struct _LinphoneCallLog *log; @@ -206,7 +207,7 @@ struct _LinphoneCall int localdesc_changed; bool_t refer_pending; - bool_t media_pending; + bool_t expect_media_in_ack; bool_t audio_muted; bool_t camera_enabled; diff --git a/coreapi/sal.c b/coreapi/sal.c index a5bcd89c2..babb2af4d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -68,8 +68,9 @@ static void sal_media_description_destroy(SalMediaDescription *md){ ms_free(md); } -void sal_media_description_ref(SalMediaDescription *md){ +SalMediaDescription * sal_media_description_ref(SalMediaDescription *md){ md->refcount++; + return md; } void sal_media_description_unref(SalMediaDescription *md){ diff --git a/include/sal/sal.h b/include/sal/sal.h index ddf94a4e2..1dfe813ba 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -233,7 +233,7 @@ typedef struct SalIsComposing { #define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 SalMediaDescription *sal_media_description_new(); -void sal_media_description_ref(SalMediaDescription *md); +SalMediaDescription * sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); bool_t sal_media_description_empty(const SalMediaDescription *md); int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2); From 14f55f24457ddd616e4b51c91e7e90c810d3b3b1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 27 Jan 2014 11:36:53 +0100 Subject: [PATCH 149/439] Update oRTP and ms2 submodule for QNX support. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 0ec5df2bd..5d17b2c51 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0ec5df2bdb94433948fe6f56ee9f9b30b2466b0c +Subproject commit 5d17b2c51483672d33d1e93c172793496ae5fa36 diff --git a/oRTP b/oRTP index d7b4d285d..0c7375aa9 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit d7b4d285d8174566c16c600a9e61abed04cb8789 +Subproject commit 0c7375aa936c096786d67dfc3757f765ebc3a2c9 From 19b9e0868ef21aa955240096926da30ce7d1235d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 27 Jan 2014 14:46:23 +0100 Subject: [PATCH 150/439] enable h263 96/98 for android --- coreapi/linphonecore.c | 5 +---- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 522c93f23..968272242 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1281,12 +1281,9 @@ 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_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); diff --git a/mediastreamer2 b/mediastreamer2 index 5d17b2c51..261012c7f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5d17b2c51483672d33d1e93c172793496ae5fa36 +Subproject commit 261012c7f2d783d133435217d3d92e383f182055 From 2c8da39ac71f12afcf9ee639f22e56b3a5cec6dd Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 27 Jan 2014 15:14:04 +0100 Subject: [PATCH 151/439] Updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 261012c7f..566ca86ae 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 261012c7f2d783d133435217d3d92e383f182055 +Subproject commit 566ca86ae2339825947a65257db100aee04c6288 From 187c55bfd8da3c7af3abcf38f5918c7760d514c2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 28 Jan 2014 12:23:11 +0100 Subject: [PATCH 152/439] add sanity checks in LinphoneEvent api --- coreapi/event.c | 30 +++++++++++++++++++++++++++--- coreapi/event.h | 5 +++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/coreapi/event.c b/coreapi/event.c index 5ddec23fd..37bbbb076 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -136,9 +136,23 @@ LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress * int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){ SalBody salbody; - if (lev->subscription_state!=LinphoneSubscriptionActive){ - ms_error("linphone_event_update_subscribe(): cannot update subscription if subscription wasn't accepted."); - return -1; + switch (lev->subscription_state){ + case LinphoneSubscriptionNone: + ms_error("linphone_event_update_subscribe(): this is not a subscribed event."); + return -1; + break; + case LinphoneSubscriptionIncomingReceived: + case LinphoneSubscriptionOutoingInit: + case LinphoneSubscriptionTerminated: + ms_error("linphone_event_update_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state)); + return -1; + break; + case LinphoneSubscriptionActive: + case LinphoneSubscriptionExpiring: + case LinphoneSubscriptionError: + case LinphoneSubscriptionPending: + /*those states are ok*/ + break; } if (lev->dir!=LinphoneSubscriptionOutgoing){ ms_error("linphone_event_deny_subscription(): cannot update an incoming subscription."); @@ -203,6 +217,12 @@ LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *re int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body){ SalBody salbody; int err; + + if (lev->publish_state==LinphonePublishNone){ + ms_error("linphone_event_update_publish(): this is not a PUBLISH event."); + return -1; + } + 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); @@ -282,3 +302,7 @@ const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){ return lev->resource_addr; } +LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){ + return lev->lc; +} + diff --git a/coreapi/event.h b/coreapi/event.h index d3f869d68..9c7bccf35 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -230,6 +230,11 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_from(const LinphoneEve **/ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev); +/** + * Returns back pointer to the LinphoneCore that created this LinphoneEvent +**/ +LINPHONE_PUBLIC LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev); + /** * @} **/ From 809123e9500c15663d51b32c7129ae150f00a6da Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 28 Jan 2014 13:59:55 +0100 Subject: [PATCH 153/439] Get supported video resolutions in Android from linphonecore --- coreapi/linphonecore.c | 24 +++++++++---------- coreapi/linphonecore_jni.cc | 20 ++++++++++++++++ .../org/linphone/core/LinphoneCore.java | 6 +++++ .../org/linphone/core/LinphoneCoreImpl.java | 6 +++++ 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 968272242..0ab3a0646 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5094,21 +5094,21 @@ 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_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, + { { MS_VIDEO_SIZE_1080P_W, MS_VIDEO_SIZE_1080P_H } , "1080p" }, + { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H } , "sxga-" }, - { { MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H } , "720p" }, - { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, - { {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H} , "svga" }, - { {MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H} , "4cif" }, - { {MS_VIDEO_SIZE_VGA_W,MS_VIDEO_SIZE_VGA_H} , "vga" }, + { { MS_VIDEO_SIZE_720P_W, MS_VIDEO_SIZE_720P_H } , "720p" }, + { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, + { { MS_VIDEO_SIZE_SVGA_W, MS_VIDEO_SIZE_SVGA_H } , "svga" }, + { { MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H } , "4cif" }, + { { MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H } , "vga" }, #ifdef __ios - { {MS_VIDEO_SIZE_IOS_MEDIUM_H,MS_VIDEO_SIZE_IOS_MEDIUM_W} , "ios-medium" }, + { { 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" }, - { {0,0} , NULL } + { { MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H } , "cif" }, + { { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" }, + { { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" }, + { { 0,0 } , NULL } }; /** diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 5839f0c4b..b44a37643 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2979,6 +2979,26 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getVideoDevice(JNIEnv *e return 0; } +extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_listSupportedVideoResolutions(JNIEnv *env, jobject thiz, jlong lc) { + const MSVideoSizeDef *pdef = linphone_core_get_supported_video_sizes((LinphoneCore *)lc); + int count = 0; + int i = 0; + for (; pdef->name!=NULL; pdef++) { + i++; + } + count = i; + + jobjectArray resolutions = (jobjectArray) env->NewObjectArray(count, env->FindClass("java/lang/String"), env->NewStringUTF("")); + pdef = linphone_core_get_supported_video_sizes((LinphoneCore *)lc); + i = 0; + for (; pdef->name!=NULL; pdef++) { + env->SetObjectArrayElement(resolutions, i, env->NewStringUTF(pdef->name)); + i++; + } + + return resolutions; +} + extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getAuthenticationToken(JNIEnv* env,jobject thiz,jlong ptr) { LinphoneCall *call = (LinphoneCall *) ptr; const char* token = linphone_call_get_authentication_token(call); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 0cedc40f8..50d109a9e 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1413,4 +1413,10 @@ public interface LinphoneCore { * @return an array of LinphoneChatRoom */ public LinphoneChatRoom[] getChatRooms(); + + /** + * Gets the linphonecore supported resolutions for video + * @return an array of String + */ + public String[] getSupportedVideoSizes(); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index f9a61acf8..bdb3540aa 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -1088,4 +1088,10 @@ class LinphoneCoreImpl implements LinphoneCore { long ptrParams =((LinphoneCallParamsImpl)params).nativePtr; return startReferedCall(nativePtr, getCallPtr(call), ptrParams); } + + private native String[] listSupportedVideoResolutions(long ptr); + @Override + public String[] getSupportedVideoSizes() { + return listSupportedVideoResolutions(nativePtr); + } } From b08e8c6b24f5913f30771a9aa56e366ae254830e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Jan 2014 15:40:33 +0100 Subject: [PATCH 154/439] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 566ca86ae..3a335de8c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 566ca86ae2339825947a65257db100aee04c6288 +Subproject commit 3a335de8c9834cfd4564bb9280a127ced2073ecd From a4c887c8192a350ccb88fafc045328949094fe3a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Jan 2014 16:22:22 +0100 Subject: [PATCH 155/439] Update oRTP submodule. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 0c7375aa9..590ab1ace 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 0c7375aa936c096786d67dfc3757f765ebc3a2c9 +Subproject commit 590ab1ace7528349344379851dff3c18585adb5e From 290671fb5480bc0df3b4478935417b5d6b28a0be Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 28 Jan 2014 17:36:10 +0100 Subject: [PATCH 156/439] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3a335de8c..9c305c87d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3a335de8c9834cfd4564bb9280a127ced2073ecd +Subproject commit 9c305c87d1483e0d23592012c7595afc541e517a From b999c757fc9c265d8d2a2e4a95e9cd0a19a42422 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 28 Jan 2014 21:22:28 +0100 Subject: [PATCH 157/439] fix rare crash in sal update oRTP --- coreapi/bellesip_sal/sal_impl.c | 9 +++++---- oRTP | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index f15b07ffb..ffabcc1e4 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -146,11 +146,12 @@ void sal_process_authentication(SalOp *op) { belle_sip_object_unref(new_request); } if (op->auth_info) sal_auth_info_delete(op->auth_info); - auth_event=(belle_sip_auth_event_t*)(auth_list->data); - op->auth_info=sal_auth_info_create(auth_event); - belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); + if (auth_list){ + auth_event=(belle_sip_auth_event_t*)(auth_list->data); + op->auth_info=sal_auth_info_create(auth_event); + belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); + } } - } static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ diff --git a/oRTP b/oRTP index 590ab1ace..86b33ede9 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 590ab1ace7528349344379851dff3c18585adb5e +Subproject commit 86b33ede9a083df63a9f999d9da9235b31b07413 From 43d5378f5206c4fd28271d8799a54fe268df69f3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 28 Jan 2014 21:39:28 +0100 Subject: [PATCH 158/439] update oRTP --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 86b33ede9..38eccb648 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 86b33ede9a083df63a9f999d9da9235b31b07413 +Subproject commit 38eccb648fa80274082fb1aa299edcd37004f1cf From a14fc017cdf9b14ad5d47750fed774bb3e4e16a9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 28 Jan 2014 22:08:58 +0100 Subject: [PATCH 159/439] fix bug regarding automatically_accept video policy --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e7a1390cc..f19ad76ef 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -614,7 +614,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); /*set video support */ md=sal_call_get_remote_media_description(op); - call->params.has_video &= !!lc->video_policy.automatically_accept; + call->params.has_video = !!lc->video_policy.automatically_accept; if (md) { // It is licit to receive an INVITE without SDP // In this case WE chose the media parameters according to policy. From d8fcf36e4b7dadaf11073e20cbb9429edd583d7c Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 27 Jan 2014 17:14:51 +0100 Subject: [PATCH 160/439] change list of supported resolution based on targetted platform --- coreapi/Makefile.am | 1 + coreapi/linphonecore.c | 38 ++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 9673552e5..0d0775be7 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -1,3 +1,4 @@ +AUTOMAKE_OPTIONS = subdir-objects GITVERSION_FILE=liblinphone_gitversion.h GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp GITDESCRIBE=`cd $(top_srcdir) && git describe --always` diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0ab3a0646..e47fe17ee 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -48,6 +48,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #endif +#ifdef __APPLE__ +#include "TargetConditionals.h" +#endif /*#define UNSTANDART_GSM_11K 1*/ @@ -5094,21 +5097,32 @@ 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_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, +#if !ANDROID & !TARGET_OS_IPHONE + { { MS_VIDEO_SIZE_1080P_W, MS_VIDEO_SIZE_1080P_H } , "1080p" }, +#endif +#if !ANDROID & !TARGET_OS_MAC /*limite to most common size because mac card cannot list supported resolutions*/ + { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H } , "sxga-" }, - { { MS_VIDEO_SIZE_720P_W, MS_VIDEO_SIZE_720P_H } , "720p" }, - { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, - { { MS_VIDEO_SIZE_SVGA_W, MS_VIDEO_SIZE_SVGA_H } , "svga" }, - { { MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H } , "4cif" }, - { { MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H } , "vga" }, -#ifdef __ios +#endif + { { MS_VIDEO_SIZE_720P_W, MS_VIDEO_SIZE_720P_H } , "720p" }, +#if !ANDROID & !TARGET_OS_MAC + { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, +#endif +#if !ANDROID && !TARGET_OS_IPHONE + { { MS_VIDEO_SIZE_SVGA_W, MS_VIDEO_SIZE_SVGA_H } , "svga" }, + { { MS_VIDEO_SIZE_4CIF_W, MS_VIDEO_SIZE_4CIF_H } , "4cif" }, +#endif + + { { MS_VIDEO_SIZE_VGA_W, MS_VIDEO_SIZE_VGA_H } , "vga" }, +#if TARGET_OS_IPHONE { { MS_VIDEO_SIZE_IOS_MEDIUM_H, MS_VIDEO_SIZE_IOS_MEDIUM_W } , "ios-medium" }, #endif - { { MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H } , "cif" }, - { { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" }, - { { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" }, - { { 0,0 } , NULL } + { { MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H } , "cif" }, +#if !TARGET_OS_MAC + { { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" }, +#endif + { { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" }, + { { 0,0 } , NULL } }; /** From af3d20dbc340fb27517435e7fa08ca7dc7e771ba Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 30 Jan 2014 11:41:39 +0100 Subject: [PATCH 161/439] Updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 9c305c87d..427dc4644 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9c305c87d1483e0d23592012c7595afc541e517a +Subproject commit 427dc46440d8f4121b7f50194ee61d9db25d2263 From be079dc88df776742e174dd496237edbe2c4ece0 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 30 Jan 2014 15:56:07 +0100 Subject: [PATCH 162/439] Fix static payload types erasing custom ones. --- coreapi/linphonecore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e47fe17ee..42851c475 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1199,7 +1199,8 @@ static void linphone_core_handle_static_payloads(LinphoneCore *lc){ for(i=0;idefault_profile,i) == NULL){ linphone_core_assign_payload_type(lc,pt,i,NULL); } } From 0eef5c5ecb66660e0484efb45bf9c89abbfb8078 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 30 Jan 2014 16:18:31 +0100 Subject: [PATCH 163/439] rework behavior for 403/401/407 auth failure to avoid loop and make sure retry are always done --- coreapi/authentication.c | 2 +- coreapi/bellesip_sal/sal_impl.c | 21 +++++-- coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_registration.c | 2 +- coreapi/linphonecore.h | 7 +++ tester/call_tester.c | 39 +++++++++++++ tester/flexisip.conf | 58 +------------------ tester/liblinphone_tester.c | 6 +- tester/liblinphone_tester.h | 1 - tester/register_tester.c | 65 ++++++++++++++++------ 10 files changed, 116 insertions(+), 86 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index bd7849832..3b7db3122 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -57,7 +57,7 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri return obj; } -static LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ +LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ LinphoneAuthInfo *obj=ms_new0(LinphoneAuthInfo,1); if (ai->username) obj->username=ms_strdup(ai->username); if (ai->userid) obj->userid=ms_strdup(ai->userid); diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ffabcc1e4..81519e542 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -116,8 +116,7 @@ void sal_process_authentication(SalOp *op) { belle_sip_auth_event_t* auth_event; belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction); - sal_add_pending_auth(op->base.root,op); - + if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request); if (!new_request) @@ -142,6 +141,8 @@ void sal_process_authentication(SalOp *op) { sal_remove_pending_auth(op->base.root,op); }else { ms_message("No auth info found for [%s]",sal_op_get_from(op)); + sal_add_pending_auth(op->base.root,op); + if (is_within_dialog) { belle_sip_object_unref(new_request); } @@ -326,15 +327,25 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_object_unref(op->pending_auth_transaction); op->pending_auth_transaction=NULL; } - op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); - sal_process_authentication(op); - return; + if (++op->auth_requests > 2) { + ms_warning("Auth info cannot be found for op [%s] after 2 attempts, giving up",sal_op_get_from(op)); + op->base.root->callbacks.auth_failure(op,op->auth_info); + sal_remove_pending_auth(op->base.root,op); + } else { + op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction); + sal_process_authentication(op); + return; + } } break; case 403: if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info); break; } + if (response_code !=401 && response_code !=407 && response_code !=403) { + /*not an auth request*/ + op->auth_requests=0; + } op->callbacks.process_response_event(op,event); } else { ms_error("Unhandled event response [%p]",event); diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index aa68feecc..5a0faa82a 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -98,6 +98,7 @@ struct SalOp{ bool_t sdp_offering; bool_t call_released; bool_t manual_refresher; + int auth_requests; /*number of auth requested for this op*/ }; diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index c02546019..2f12d4533 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -63,7 +63,7 @@ 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) + if (status_code==403 || status_code==401 || status_code==407 ) op->base.root->callbacks.auth_failure(op,op->auth_info); } } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 0ad6030da..56f33b0d2 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -918,6 +918,13 @@ typedef struct _LinphoneAuthInfo LinphoneAuthInfo; LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, const char *passwd, const char *ha1,const char *realm, const char *domain); +/** + * @addtogroup authentication + * Instanciate a new auth info with values from source + * @param source auth info object to be cloned + * @return newly created auth info + */ +LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo* source); LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); LINPHONE_PUBLIC void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); LINPHONE_PUBLIC void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); diff --git a/tester/call_tester.c b/tester/call_tester.c index 05a394423..0333df962 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1479,6 +1479,43 @@ static void call_established_with_rejected_reinvite_with_error(void) { linphone_core_manager_destroy(pauline); } +static void call_rejected_because_wrong_credentials_with_params(const char* user_agent) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneAuthInfo* good_auth_info=linphone_auth_info_clone((LinphoneAuthInfo*)(linphone_core_get_auth_info_list(marie->lc)->data)); + LinphoneAuthInfo* wrong_auth_info=linphone_auth_info_clone(good_auth_info); + + if (user_agent) { + linphone_core_set_user_agent(marie->lc,user_agent,NULL); + } + linphone_core_clear_all_auth_info(marie->lc); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(marie->lc,marie->identity)); + + CU_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_auth_info_requested,1)); + + linphone_auth_info_set_passwd(wrong_auth_info,"passecretdutout"); + + /*automatically re-inititae the call*/ + linphone_core_add_auth_info(marie->lc,wrong_auth_info); + + + CU_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCallError,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_auth_info_requested,2); + + /*to make sure unregister will work*/ + linphone_core_clear_all_auth_info(marie->lc); + linphone_core_add_auth_info(marie->lc,good_auth_info); + + linphone_core_manager_destroy(marie); +} +static void call_rejected_because_wrong_credentials() { + call_rejected_because_wrong_credentials_with_params(NULL); +} + +static void call_rejected_without_403_because_wrong_credentials() { + call_rejected_because_wrong_credentials_with_params("tester-no-403"); +} + #ifdef VIDEO_ENABLED #endif @@ -1511,6 +1548,8 @@ test_t call_tests[] = { { "SRTP ice call", srtp_ice_call }, #endif { "Call with privacy", call_with_privacy }, + { "Call rejected because of wrong credential", call_rejected_because_wrong_credentials}, + { "Call rejected without 403 because of wrong credential", call_rejected_without_403_because_wrong_credentials}, { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, { "Unattended call transfer", unattended_call_transfer }, diff --git a/tester/flexisip.conf b/tester/flexisip.conf index b4d39a5c0..af571c1c3 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -86,9 +86,6 @@ ban-duration=60 # 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 @@ -123,6 +120,9 @@ contact-verified-param=verified # Default value: false enabled=true + +no-403=user-agent contains 'tester-no-403' + # A request/response enters module if the boolean filter evaluates # to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain # in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') @@ -345,59 +345,7 @@ generated-contact-route= # Default value: generated-contact-expected-realm= -## -## This module performs push notifications -## -[module::PushNotification] -# Indicate whether the module is activated. -# Default value: false -enabled=false -# A request/response enters module if the boolean filter evaluates -# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain -# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') -# && (user-agent == 'Linphone v2') -# Default value: -filter= - -# Number of second to wait before sending a push notification to -# device(if <=0 then disabled) -# Default value: 5 -timeout=5 - -# Maximum number of notifications queued for each client -# Default value: 10 -max-queue-size=10 - -# Enable push notification for apple devices -# Default value: true -apple=true - -# Path to directory where to find Apple Push Notification service -# certificates. They should bear the appid of the application, suffixed -# by the release mode and .pem extension. For example: org.linphone.dev.pem -# org.linphone.prod.pem com.somephone.dev.pem etc... The files should -# be .pem format, and made of certificate followed by private key. -# Default value: /etc/flexisip/apn -apple-certificate-dir=/etc/flexisip/apn - -# Enable push notification for android devices -# Default value: true -google=true - -# List of couple projectId:ApiKey for each android project which -# support push notifications -# Default value: -google-projects-api-keys= - -## -## The purpose of the ContactRouteInserter module is to masquerade -## the contact header of incoming registers that are not handled -## locally (think about flexisip used as a SBC gateway) in such a -## way that it is then possible to route back outgoing invites to -## the original address. It is a kind of similar mechanism as Record-Route, -## but for REGISTER. -## [module::ContactRouteInserter] # Indicate whether the module is activated. # Default value: true diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index dbbba9a46..8a889157a 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -70,17 +70,13 @@ LinphoneAddress * create_linphone_address(const char * domain) { return addr; } -void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { +static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { stats* counters; - LinphoneAuthInfo *info; ms_message("Auth info requested for user id [%s] at realm [%s]\n" ,username ,realm); counters = get_stats(lc); counters->number_of_auth_info_requested++; - info=linphone_auth_info_new(test_username,NULL,test_password,NULL,realm,domain); /*create authentication structure from identity*/ - linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ - } diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 93bde611a..ac5302458 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -198,7 +198,6 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); -void 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 6ee79f9cd..6e5c929a5 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -22,6 +22,26 @@ #include "private.h" #include "liblinphone_tester.h" +static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { + stats* counters; + + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + counters = get_stats(lc); + counters->number_of_auth_info_requested++; + +} + +static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { + LinphoneAuthInfo *info; + auth_info_requested2(lc,realm,username,domain); + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,realm,domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ +} + + + static LinphoneCoreManager* create_lcm_with_auth(unsigned int with_auth) { LinphoneCoreManager* mgr=linphone_core_manager_new(NULL); @@ -108,7 +128,8 @@ static void register_with_refresh_base_3(LinphoneCore* lc linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } } - if (linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonBadCredentials) + if (linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonBadCredentials + || (counters->number_of_auth_info_requested>2 &&linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonUnauthorized)) /*no need to continue if auth cannot be found*/ break; /*no need to continue*/ ms_usleep(100000); } @@ -261,6 +282,8 @@ static void authenticated_register_with_no_initial_credentials(){ mgr = linphone_core_manager_new(NULL); + mgr->lc->vtable.auth_info_requested=auth_info_requested; + counters= get_stats(mgr->lc); counters->number_of_auth_info_requested=0; register_with_refresh(mgr,FALSE,auth_domain,route); @@ -268,14 +291,6 @@ 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, const char *domain) { - stats* counters; - ms_message("Auth info requested for user id [%s] at realm [%s]\n" - ,username - ,realm); - counters = get_stats(lc); - counters->number_of_auth_info_requested++; -} static void authenticated_register_with_late_credentials(){ LinphoneCoreManager *mgr; @@ -286,10 +301,10 @@ static void authenticated_register_with_late_credentials(){ sprintf(route,"sip:%s",test_route); mgr = linphone_core_manager_new(NULL); - mgr->lc->vtable.auth_info_requested=auth_info_requested2; + counters = get_stats(mgr->lc); register_with_refresh_base_2(mgr->lc,FALSE,auth_domain,route,TRUE,transport); - CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,2); /*1 registration error = 2 auth requested*/ linphone_core_manager_destroy(mgr); } @@ -306,10 +321,10 @@ static void authenticated_register_with_wrong_late_credentials(){ 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_auth_info_requested,3); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,2); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2); test_password=saved_test_passwd; @@ -317,7 +332,7 @@ static void authenticated_register_with_wrong_late_credentials(){ linphone_core_manager_destroy(mgr); } -static void authenticated_register_with_wrong_credentials(){ +static void authenticated_register_with_wrong_credentials_with_params(const char* user_agent) { LinphoneCoreManager *mgr; stats* counters; LCSipTransports transport = {5070,5070,0,5071}; @@ -327,15 +342,28 @@ static void authenticated_register_with_wrong_credentials(){ sprintf(route,"sip:%s",test_route); mgr=linphone_core_manager_new(NULL); + mgr->lc->vtable.auth_info_requested=auth_info_requested2; - + + sal_set_refresher_retry_after(mgr->lc->sal,500); + if (user_agent) { + linphone_core_set_user_agent(mgr->lc,user_agent,NULL); + } linphone_core_add_auth_info(mgr->lc,info); /*add wrong authentication info to LinphoneCore*/ counters = get_stats(mgr->lc); - register_with_refresh_base_3(mgr->lc,TRUE,auth_domain,route,TRUE,transport,LinphoneRegistrationFailed); - CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + register_with_refresh_base_3(mgr->lc,TRUE,auth_domain,route,FALSE,transport,LinphoneRegistrationFailed); + //CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,3); register_with_refresh_base_3 does not alow to precisely check number of number_of_auth_info_requested + /*wait for retry*/ + CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&counters->number_of_auth_info_requested,4)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,1); linphone_core_manager_destroy(mgr); } - +static void authenticated_register_with_wrong_credentials() { + authenticated_register_with_wrong_credentials_with_params(NULL); +} +static void authenticated_register_with_wrong_credentials_without_403() { + authenticated_register_with_wrong_credentials_with_params("tester-no-403"); +} static LinphoneCoreManager* configure_lcm(void) { LinphoneCoreManager *mgr=linphone_core_manager_new( "multi_account_lrc"); stats *counters=&mgr->stat; @@ -611,6 +639,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 }, + { "Digest auth with wrong credentials without 403", authenticated_register_with_wrong_credentials_without_403}, { "Authenticated register with wrong late credentials", authenticated_register_with_wrong_late_credentials}, { "Authenticated register with late credentials", authenticated_register_with_late_credentials }, { "Register with refresh", simple_register_with_refresh }, From 2c094bdea1f9ea6382df96d3667b74f80913f0f4 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 30 Jan 2014 17:19:10 +0100 Subject: [PATCH 164/439] Fix incall timeout calculation --- coreapi/linphonecore.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 42851c475..5397e4755 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2244,12 +2244,15 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_decline_call(lc,call,decline_reason); } } - if (lc->sip_conf.in_call_timeout > 0 && elapsed>lc->sip_conf.in_call_timeout) { + if ( (lc->sip_conf.in_call_timeout > 0) + && (call->media_start_time != 0) + && ((curtime - call->media_start_time) > lc->sip_conf.in_call_timeout)) + { ms_message("in call timeout (%i)",lc->sip_conf.in_call_timeout); linphone_core_terminate_call(lc,call); } } - + if (linphone_core_video_preview_enabled(lc)){ if (lc->previewstream==NULL && lc->calls==NULL) toggle_video_preview(lc,TRUE); From d66f586542cbee6e1ed48f12fb469c87f04a4ae4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 31 Jan 2014 09:44:14 +0100 Subject: [PATCH 165/439] fix test in event suite --- 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 9dfaf2af7..9cff70f9d 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -164,7 +164,7 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes }else if (refresh_type==ManualRefresh){ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionExpiring,1,4000)); linphone_event_update_subscribe(lev,NULL); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,2000)); } if (terminated_by_subscriber){ From 920f5d052d899a10687308c1d8a5f3de8055c727 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 31 Jan 2014 10:58:55 +0100 Subject: [PATCH 166/439] Add linphone_call_get_ring_duration() method --- coreapi/linphonecall.c | 11 +++++++++++ coreapi/linphonecore.h | 1 + 2 files changed, 12 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f19ad76ef..53bc6ba8b 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1082,6 +1082,17 @@ int linphone_call_get_duration(const LinphoneCall *call){ return time(NULL)-call->media_start_time; } +/** + * Returns the call ring duration in seconds. This is only useful if the call is in state #LinphoneCallOutgoingRinging + * @param call the call + * @return ringing time + */ +int linphone_call_get_ring_duration(const LinphoneCall* call){ + if( call->start_time == 0) return 0; + return time(NULL)-call->start_time; +} + + /** * Returns the call object this call is replacing, if any. * Call replacement can occur during call transfers. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 56f33b0d2..5edb9001f 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -639,6 +639,7 @@ LINPHONE_PUBLIC LinphoneCall *linphone_call_get_transferer_call(const LinphoneCa LINPHONE_PUBLIC LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call); LINPHONE_PUBLIC int linphone_call_get_duration(const LinphoneCall *call); +LINPHONE_PUBLIC int linphone_call_get_ring_duration(const LinphoneCall* call); LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); From 7240e93a3c31d45ef376d887da3662d02b0c62bc Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 31 Jan 2014 11:09:25 +0100 Subject: [PATCH 167/439] Added missing ref causing crash on unref on Android --- coreapi/linphonecore_jni.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b44a37643..6b272d962 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3673,7 +3673,9 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_unref(JNIEnv *en * Signature: ()J */ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceModelImpl__(JNIEnv *env, jobject jobj) { - return (jlong)linphone_presence_model_new(); + LinphonePresenceModel *model = linphone_presence_model_new(); + model = linphone_presence_model_ref(model); + return (jlong)model; } /* @@ -3685,6 +3687,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceMode LinphonePresenceModel *model; const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; model = linphone_presence_model_new_with_activity((LinphonePresenceActivityType)type, cdescription); + model = linphone_presence_model_ref(model); if (cdescription) env->ReleaseStringUTFChars(description, cdescription); return (jlong)model; } @@ -3701,6 +3704,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceMode const char *cnote = note ? env->GetStringUTFChars(note, NULL) : NULL; const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL; model = linphone_presence_model_new_with_activity_and_note((LinphonePresenceActivityType)type, cdescription, cnote, clang); + model = linphone_presence_model_ref(model); if (cdescription) env->ReleaseStringUTFChars(description, cdescription); if (cnote) env->ReleaseStringUTFChars(note, cnote); if (clang) env->ReleaseStringUTFChars(lang, clang); @@ -3969,6 +3973,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceActivityImpl_newPresenceA LinphonePresenceActivity *activity; const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; activity = linphone_presence_activity_new((LinphonePresenceActivityType)type, cdescription); + activity = linphone_presence_activity_ref(activity); if (cdescription) env->ReleaseStringUTFChars(description, cdescription); return (jlong)activity; } @@ -4049,6 +4054,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_newPresenceSe const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; const char *ccontact = contact ? env->GetStringUTFChars(contact, NULL) : NULL; service = linphone_presence_service_new(cid, (LinphonePresenceBasicStatus)basic_status, ccontact); + service = linphone_presence_service_ref(service); if (cid) env->ReleaseStringUTFChars(id, cid); if (ccontact) env->ReleaseStringUTFChars(contact, ccontact); return (jlong)service; @@ -4184,6 +4190,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_newPresencePer LinphonePresencePerson *person; const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; person = linphone_presence_person_new(cid); + person = linphone_presence_person_ref(person); if (cid) env->ReleaseStringUTFChars(id, cid); return (jlong)person; } @@ -4356,6 +4363,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceNoteImpl_newPresenceNoteI const char *ccontent = content ? env->GetStringUTFChars(content, NULL) : NULL; const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL; note = linphone_presence_note_new(ccontent, clang); + note = linphone_presence_note_ref(note); if (clang) env->ReleaseStringUTFChars(lang, clang); if (ccontent) env->ReleaseStringUTFChars(content, ccontent); return (jlong)note; From ba063681674c12b4a66c360df2aa0cf8a657d764 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 31 Jan 2014 12:01:38 +0100 Subject: [PATCH 168/439] Revert linphone_call_get_ring_duration() method, and use the call log to get ring time. Also moved start_time considerations to the call log to clean up a bit. --- coreapi/linphonecall.c | 138 +++++++++++++++++++---------------------- coreapi/linphonecore.c | 10 +-- coreapi/linphonecore.h | 1 - coreapi/private.h | 1 - 4 files changed, 68 insertions(+), 82 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 53bc6ba8b..20208eea7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -51,7 +51,7 @@ static bool_t generate_b64_crypto_key(int key_length, char* key_out, size_t key_ ms_free(tmp); return FALSE; } - + b64_size = b64_encode((const char*)tmp, key_length, NULL, 0); if (b64_size == 0) { ms_error("Failed to get b64 result size"); @@ -137,7 +137,7 @@ static void linphone_call_audiostream_encryption_changed(void *data, bool_t encr call = (LinphoneCall *)data; call->audiostream_encrypted=encrypted; - + if (encrypted && call->core->vtable.display_status != NULL) { snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token); call->core->vtable.display_status(call->core, status); @@ -234,7 +234,7 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ int i; SalMediaDescription *old_md=call->localdesc; bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); - + for(i=0; in_active_streams; i++) { if (md->streams[i].proto == SalProtoRtpSavp) { if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ @@ -272,17 +272,17 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * if (call->dest_proxy) me=linphone_proxy_config_get_identity(call->dest_proxy); - else + 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=(call->biggestdesc ? call->biggestdesc->n_total_streams : 1); - + strncpy(md->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); - + if (call->params.down_bw) md->bandwidth=call->params.down_bw; else md->bandwidth=linphone_core_get_download_bandwidth(lc); @@ -293,7 +293,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * 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) ? + md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? SalProtoRtpSavp : SalProtoRtpAvp; md->streams[0].type=SalAudio; if (call->params.down_ptime) @@ -329,7 +329,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * } setup_encryption_keys(call,md); - + update_media_description_from_stun(md,&call->ac,&call->vc); if (call->ice_session != NULL) { linphone_core_update_local_media_description_from_ice(md, call->ice_session); @@ -444,12 +444,11 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->refcnt=1; call->state=LinphoneCallIdle; call->transfer_state = LinphoneCallIdle; - call->start_time=time(NULL); call->media_start_time=0; call->log=linphone_call_log_new(call, from, to); call->owns_call_log=TRUE; call->camera_enabled=TRUE; - + linphone_core_get_audio_port_range(call->core, &min_port, &max_port); if (min_port == max_port) { /* Used fixed RTP audio port. */ @@ -516,7 +515,7 @@ void linphone_call_create_op(LinphoneCall *call){ * Choose IP version we are going to use for RTP socket. * The algorithm is as follows: * - if ipv6 is disabled at the core level, it is always AF_INET - * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6. + * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6. * - Otherwise, if the call is done through a known proxy config, then use the information obtained during REGISTER * to know if IPv6 is supported by the server. **/ @@ -533,14 +532,14 @@ static void linphone_call_outgoing_select_ip_version(LinphoneCall *call, Linphon 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_call_outgoing_select_ip_version(call,to,cfg); linphone_core_get_local_ip(lc,call->af,call->localip); linphone_call_init_common(call,from,to); _linphone_call_params_copy(&call->params,params); - + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { call->ice_session = ice_session_new(); ice_session_set_role(call->ice_session, IR_Controlling); @@ -555,7 +554,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr } } #endif //BUILD_UPNP - + discover_mtu(lc,linphone_address_get_domain (to)); if (params->referer){ call->referer=linphone_call_ref(params->referer); @@ -605,7 +604,7 @@ 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); - + /* * Initialize call parameters according to incoming call parameters. This is to avoid to ask later (during reINVITEs) for features that the remote * end apparently does not support. This features are: privacy, video @@ -620,7 +619,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro // In this case WE chose the media parameters according to policy. call->params.has_video &= linphone_core_media_description_contains_video_stream(md); } - + switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: call->ice_session = ice_session_new(); @@ -657,7 +656,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro default: break; } - + discover_mtu(lc,linphone_address_get_domain(from)); return call; } @@ -760,7 +759,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const } 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. @@ -916,7 +915,7 @@ static bool_t is_video_active(const SalStreamDescription *sd){ /** * Returns call parameters proposed by remote. - * + * * This is useful when receiving an incoming call, to know whether the remote party * supports video, encryption or whatever. **/ @@ -1082,17 +1081,6 @@ int linphone_call_get_duration(const LinphoneCall *call){ return time(NULL)-call->media_start_time; } -/** - * Returns the call ring duration in seconds. This is only useful if the call is in state #LinphoneCallOutgoingRinging - * @param call the call - * @return ringing time - */ -int linphone_call_get_ring_duration(const LinphoneCall* call){ - if( call->start_time == 0) return 0; - return time(NULL)-call->start_time; -} - - /** * Returns the call object this call is replacing, if any. * Call replacement can occur during call transfers. @@ -1117,7 +1105,7 @@ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){ MSWebCam *nowebcam=get_nowebcam_device(); if (call->camera_enabled!=enable && lc->video_conf.device!=nowebcam){ video_stream_change_camera(call->videostream, - enable ? lc->video_conf.device : nowebcam); + enable ? lc->video_conf.device : nowebcam); } } call->camera_enabled=enable; @@ -1202,11 +1190,11 @@ bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) /** * @ingroup call_control - * Indicate low bandwith mode. + * Indicate low bandwith mode. * Configuring a call to low bandwidth mode will result in the core to activate several settings for the call in order to ensure that bitrate usage * is lowered to the minimum possible. Typically, ptime (packetization time) will be increased, audio codec's output bitrate will be targetted to 20kbit/s provided * that it is achievable by the codec selected after SDP handshake. Video is automatically disabled. - * + * **/ void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){ cp->low_bandwidth=enabled; @@ -1349,13 +1337,13 @@ void linphone_call_params_destroy(LinphoneCallParams *p){ #ifdef TEST_EXT_RENDERER static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){ ms_message("rendercb, local buffer=%p, remote buffer=%p", - local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL); + local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL); } #endif #ifdef VIDEO_ENABLED static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){ - LinphoneCall* call = (LinphoneCall*) user_pointer; + LinphoneCall* call = (LinphoneCall*) user_pointer; ms_warning("In linphonecall.c: video_stream_event_cb"); switch (event_id) { case MS_VIDEO_DECODER_DECODING_ERRORS: @@ -1451,7 +1439,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ 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,call->af==AF_INET6); if (dscp!=-1) video_stream_set_dscp(call->videostream,dscp); @@ -1550,7 +1538,7 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute if (recv_gain != 0) { linphone_core_set_playback_gain_db (lc,recv_gain); } - + if (st->volsend){ ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal); speed=lp_config_get_float(lc->config,"sound","el_speed",-1); @@ -1591,7 +1579,7 @@ static void post_configure_audio_streams(LinphoneCall*call){ if (lc->vtable.dtmf_received!=NULL){ audio_stream_play_received_dtmfs(call->audiostream,FALSE); } - if (call->record_active) + if (call->record_active) linphone_call_start_recording(call); } @@ -1671,18 +1659,18 @@ static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){ static bool_t linphone_call_sound_resources_available(LinphoneCall *call){ LinphoneCore *lc=call->core; LinphoneCall *current=linphone_core_get_current_call(lc); - return !linphone_core_is_in_conference(lc) && + return !linphone_core_is_in_conference(lc) && (current==NULL || current==call); } static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) { - int i; - for(i=0; iresultdesc, - SalProtoRtpSavp,SalAudio); + SalProtoRtpSavp,SalAudio); /* no savp audio stream, use avp */ if (!stream) stream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalAudio); + SalProtoRtpAvp,SalAudio); if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){ playcard=lc->sound_conf.lsd_card ? @@ -1789,7 +1777,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna setup_ring_player(lc,call); } audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); - + /* valid local tags are > 0 */ if (stream->proto == SalProtoRtpSavp) { local_st_desc=sal_media_description_find_stream(call->localdesc,SalProtoRtpSavp,SalAudio); @@ -1797,7 +1785,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna if (crypto_idx >= 0) { audio_stream_enable_srtp( - call->audiostream, + call->audiostream, stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, stream->crypto[0].master_key); @@ -1824,21 +1812,21 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna int used_pt=-1; /* look for savp stream first */ const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpSavp,SalVideo); + SalProtoRtpSavp,SalVideo); char rtcp_tool[128]={0}; snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); - + /* no savp audio stream, use avp */ if (!vstream) vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalVideo); - + SalProtoRtpAvp,SalVideo); + /* shutdown preview */ if (lc->previewstream!=NULL) { video_preview_stop(lc->previewstream); lc->previewstream=NULL; } - + if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) { const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr; @@ -1852,7 +1840,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna call->current_params.has_video=TRUE; video_stream_enable_adaptive_bitrate_control(call->videostream, - linphone_core_adaptive_rate_control_enabled(lc)); + linphone_core_adaptive_rate_control_enabled(lc)); video_stream_enable_adaptive_jittcomp(call->videostream, linphone_core_video_adaptive_jittcomp_enabled(lc)); video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc)); video_stream_enable_self_view(call->videostream,lc->video_conf.selfview); @@ -1861,7 +1849,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna if (lc->preview_window_id!=0) video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id); video_stream_use_preview_video_window (call->videostream,lc->use_preview_window); - + if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){ cam=get_nowebcam_device(); dir=VideoStreamSendOnly; @@ -1894,15 +1882,15 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna used_pt, linphone_core_get_video_jittcomp(lc), cam); video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool); } - + if (vstream->proto == SalProtoRtpSavp) { const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc, - SalProtoRtpSavp,SalVideo); - + SalProtoRtpSavp,SalVideo); + video_stream_enable_strp( - call->videostream, + call->videostream, vstream->crypto[0].algo, - local_st_desc->crypto[0].master_key, + local_st_desc->crypto[0].master_key, vstream->crypto[0].master_key ); call->videostream_encrypted=TRUE; @@ -1923,7 +1911,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc); #ifdef VIDEO_ENABLED const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalVideo); + SalProtoRtpAvp,SalVideo); #endif call->current_params.audio_codec = NULL; @@ -1957,7 +1945,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut 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{ @@ -2114,7 +2102,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ if (call->audiostream || call->videostream) { linphone_call_stop_audio_stream(call); linphone_call_stop_video_stream(call); - + if (call->core->msevq != NULL) { ms_event_queue_skip(call->core->msevq); } @@ -2658,16 +2646,16 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse void linphone_call_log_completed(LinphoneCall *call){ LinphoneCore *lc=call->core; - call->log->duration=time(NULL)-call->start_time; + call->log->duration=time(NULL)-call->log->start_date_time; if (call->log->status==LinphoneCallMissed){ char *info; lc->missed_calls++; info=ortp_strdup_printf(ngettext("You have missed %i call.", - "You have missed %i calls.", lc->missed_calls), - lc->missed_calls); - if (lc->vtable.display_status!=NULL) - lc->vtable.display_status(lc,info); + "You have missed %i calls.", lc->missed_calls), + lc->missed_calls); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,info); ms_free(info); } lc->call_logs=ms_list_prepend(lc->call_logs,(void *)call->log); @@ -2717,7 +2705,7 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied. * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0. * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0. - * + * * cx and cy are updated in return in case their coordinates were too excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video. **/ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) { @@ -2725,7 +2713,7 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, if (vstream && vstream->output) { float zoom[3]; float halfsize; - + if (zoom_factor < 1) zoom_factor = 1; halfsize = 0.5 * 1.0 / zoom_factor; @@ -2738,11 +2726,11 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, *cy = 0 + halfsize; if ((*cy + halfsize) > 1) *cy = 1 - halfsize; - + zoom[0] = zoom_factor; zoom[1] = *cx; zoom[2] = *cy; - ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom); + ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom); }else ms_warning("Could not apply zoom: video output wasn't activated."); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5397e4755..e00ada56d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -120,7 +120,7 @@ static void set_call_log_date(LinphoneCallLog *cl, time_t start_time){ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ LinphoneCallLog *cl=ms_new0(LinphoneCallLog,1); cl->dir=call->dir; - cl->start_date_time=call->start_time; + cl->start_date_time=time(NULL); set_call_log_date(cl,cl->start_date_time); cl->from=from; cl->to=to; @@ -2211,7 +2211,7 @@ void linphone_core_iterate(LinphoneCore *lc){ calls= lc->calls; while(calls!= NULL){ call = (LinphoneCall *)calls->data; - elapsed = curtime-call->start_time; + elapsed = curtime-call->log->start_date_time; /* get immediately a reference to next one in case the one we are going to examine is destroy and removed during linphone_core_start_invite() */ @@ -2766,7 +2766,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const /* Defer the start of the call after the ICE gathering process. */ linphone_call_init_media_streams(call); linphone_call_start_media_streams_for_ice_gathering(call); - call->start_time=time(NULL); + call->log->start_date_time=time(NULL); if (linphone_core_gather_ice_candidates(lc,call)<0) { /* Ice candidates gathering failed, proceed with the call anyway. */ linphone_call_delete_ice_session(call); @@ -2778,7 +2778,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { #ifdef BUILD_UPNP linphone_call_init_media_streams(call); - call->start_time=time(NULL); + call->log->start_date_time=time(NULL); if (linphone_core_update_upnp(lc,call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ linphone_call_delete_upnp_session(call); @@ -2800,7 +2800,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const call->ping_op=sal_op_new(lc->sal); sal_ping(call->ping_op,from,real_url); sal_op_set_user_pointer(call->ping_op,call); - call->start_time=time(NULL); + call->log->start_date_time=time(NULL); defer = TRUE; } } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 5edb9001f..56f33b0d2 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -639,7 +639,6 @@ LINPHONE_PUBLIC LinphoneCall *linphone_call_get_transferer_call(const LinphoneCa LINPHONE_PUBLIC LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call); LINPHONE_PUBLIC LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call); LINPHONE_PUBLIC int linphone_call_get_duration(const LinphoneCall *call); -LINPHONE_PUBLIC int linphone_call_get_ring_duration(const LinphoneCall* call); LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); LINPHONE_PUBLIC void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); diff --git a/coreapi/private.h b/coreapi/private.h index 32d3553a0..e16ed9c5c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -168,7 +168,6 @@ struct _LinphoneCall SalOp *op; SalOp *ping_op; char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */ - time_t start_time; /*time at which the call was initiated*/ time_t media_start_time; /*time at which it was accepted, media streams established*/ LinphoneCallState state; LinphoneCallState prevstate; From b1663d2cc60dd82a7db4f7412dd0cc22dde2ab40 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 3 Feb 2014 10:44:50 +0100 Subject: [PATCH 169/439] fix potential crash in linphone_call_enable_camera() --- coreapi/linphonecall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 20208eea7..87189d7f8 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1100,7 +1100,8 @@ LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){ **/ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){ #ifdef VIDEO_ENABLED - if (call->videostream!=NULL && call->videostream->ms.ticker!=NULL){ + if ((call->state==LinphoneCallStreamsRunning || call->state==LinphoneCallOutgoingEarlyMedia || call->state==LinphoneCallIncomingEarlyMedia) + && call->videostream!=NULL ){ LinphoneCore *lc=call->core; MSWebCam *nowebcam=get_nowebcam_device(); if (call->camera_enabled!=enable && lc->video_conf.device!=nowebcam){ From 941883df0752dcec9ba8d5fdb5bc33027be58192 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 3 Feb 2014 16:58:28 +0100 Subject: [PATCH 170/439] Added option to disable ms2 opensles soundcard compilation for Android --- build/android/Android.mk | 5 ++++- mediastreamer2 | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index 4f4e9954d..8dfe0cb84 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -105,7 +105,10 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../externals/libxml2/include \ $(LOCAL_PATH)/../../externals/build/libxml2 -LOCAL_LDLIBS += -llog -lOpenSLES -ldl +ifeq ($(BUILD_OPENSLES_SOUNDCARD),1) + LOCAL_LDLIBS += -lOpenSLES +endif +LOCAL_LDLIBS += -llog -ldl LOCAL_STATIC_LIBRARIES := \ cpufeatures \ diff --git a/mediastreamer2 b/mediastreamer2 index 427dc4644..e2ea92a34 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 427dc46440d8f4121b7f50194ee61d9db25d2263 +Subproject commit e2ea92a34d2577910115e20574f3f1e6474850da From 92f81c8d07f6c5a41c8d240a5c6b6a31a9b211ed Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 3 Feb 2014 17:47:50 +0100 Subject: [PATCH 171/439] Use right functions to free and duplicate strings. --- coreapi/lpconfig.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 60e944882..eaeaad71a 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -200,8 +200,8 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ if (item==NULL){ lp_section_add_item(cur,lp_item_new(key,pos1)); }else{ - ms_free(item->value); - item->value=strdup(pos1); + ortp_free(item->value); + item->value=ortp_strdup(pos1); } /*ms_message("Found %s=%s",key,pos1);*/ }else{ From 0ca6aedeca4b693d39aaf6fa48aef62e63f4cb49 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 4 Feb 2014 11:01:25 +0100 Subject: [PATCH 172/439] change telephone-event supported codes --- coreapi/linphonecore.c | 2 +- tester/call_tester.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e00ada56d..3ca34e0ba 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1261,7 +1261,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(lc,&payload_type_speex_nb,110,"vbr=on"); linphone_core_assign_payload_type(lc,&payload_type_speex_wb,111,"vbr=on"); linphone_core_assign_payload_type(lc,&payload_type_speex_uwb,112,"vbr=on"); - linphone_core_assign_payload_type(lc,&payload_type_telephone_event,101,"0-11"); + linphone_core_assign_payload_type(lc,&payload_type_telephone_event,101,"0-15"); linphone_core_assign_payload_type(lc,&payload_type_g722,9,NULL); #if defined(ANDROID) || defined (__IPHONE_OS_VERSION_MIN_REQUIRED) diff --git a/tester/call_tester.c b/tester/call_tester.c index 0333df962..f0fd07461 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1033,11 +1033,19 @@ static void early_media_call(void) { CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); + + wait_for_until(pauline->lc,marie->lc,NULL,0,1000); + + /*added because a bug related to early-media caused the Connected state to be reached two times*/ + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected,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); } From 0dae0d3320c997a2b8c398cfb5838ed75cbd8654 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 4 Feb 2014 11:29:14 +0100 Subject: [PATCH 173/439] reset op auth count in case of io error --- coreapi/bellesip_sal/sal_impl.c | 5 ++++- tester/flexisip.conf | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 81519e542..1c2df0879 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -171,6 +171,8 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),belle_sip_client_transaction_t)) { client_transaction=BELLE_SIP_CLIENT_TRANSACTION(belle_sip_io_error_event_get_source(event)); op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); + /*also reset auth count on IO error*/ + op->auth_requests=0; if (op->callbacks.process_io_error) { op->callbacks.process_io_error(op,event); } @@ -328,7 +330,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even op->pending_auth_transaction=NULL; } if (++op->auth_requests > 2) { - ms_warning("Auth info cannot be found for op [%s] after 2 attempts, giving up",sal_op_get_from(op)); + ms_warning("Auth info cannot be found for op [%s/%s] after 2 attempts, giving up",sal_op_get_from(op) + ,sal_op_get_to(op)); op->base.root->callbacks.auth_failure(op,op->auth_info); sal_remove_pending_auth(op->base.root,op); } else { diff --git a/tester/flexisip.conf b/tester/flexisip.conf index af571c1c3..571d90731 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -293,7 +293,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 sip2.linphone.org +reg-domains=localhost sip.example.org sipopen.example.org auth1.example.org sip2.linphone.org client.example.org # Maximum number of registered contacts of an address of record. # Default value: 15 From 10b8224e38fec5895aec47b888f11c6a5f19f2b1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 4 Feb 2014 11:44:47 +0100 Subject: [PATCH 174/439] Renamed/added comments for some call stats functions + use those functions in JNI wrapper for Android --- coreapi/linphonecall.c | 30 ++++++++++-- coreapi/linphonecore.h | 10 ++-- coreapi/linphonecore_jni.cc | 95 ++----------------------------------- 3 files changed, 35 insertions(+), 100 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 87189d7f8..8511375ad 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2270,7 +2270,11 @@ const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) { return stats; } -float linphone_call_stats_update_sender_loss_rate(const LinphoneCallStats *stats) { +/** + * Get the local loss rate since last report + * @return The sender loss rate +**/ +float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats) { const report_block_t *srb = NULL; if (!stats || !stats->sent_rtcp) @@ -2287,7 +2291,11 @@ float linphone_call_stats_update_sender_loss_rate(const LinphoneCallStats *stats return 100.0 * report_block_get_fraction_lost(srb) / 256.0; } -float linphone_call_stats_update_receiver_loss_rate(const LinphoneCallStats *stats) { +/** + * Gets the remote reported loss rate since last report + * @return The receiver loss rate +**/ +float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats) { const report_block_t *rrb = NULL; if (!stats || !stats->received_rtcp) @@ -2304,7 +2312,11 @@ float linphone_call_stats_update_receiver_loss_rate(const LinphoneCallStats *sta return 100.0 * report_block_get_fraction_lost(rrb) / 256.0; } -float linphone_call_stats_update_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { +/** + * Gets the local interarrival jitter + * @return The interarrival jitter at last emitted sender report +**/ +float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { const LinphoneCallParams *params; const PayloadType *pt; const report_block_t *srb = NULL; @@ -2332,7 +2344,11 @@ float linphone_call_stats_update_sender_interarrival_jitter(const LinphoneCallSt return (float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate; } -float linphone_call_stats_update_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { +/** + * Gets the remote reported interarrival jitter + * @return The interarrival jitter at last received receiver report +**/ +float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call) { const LinphoneCallParams *params; const PayloadType *pt; const report_block_t *rrb = NULL; @@ -2360,7 +2376,11 @@ float linphone_call_stats_update_receiver_interarrival_jitter(const LinphoneCall return (float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate; } -uint64_t linphone_call_stats_update_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call) { +/** + * Gets the cumulative number of late packets + * @return The cumulative number of late packets +**/ +uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call) { rtp_stats_t rtp_stats; if (!stats || !call) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 56f33b0d2..b71118dd3 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -585,11 +585,11 @@ struct _LinphoneCallStats { LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); -LINPHONE_PUBLIC float linphone_call_stats_update_sender_loss_rate(const LinphoneCallStats *stats); -LINPHONE_PUBLIC float linphone_call_stats_update_receiver_loss_rate(const LinphoneCallStats *stats); -LINPHONE_PUBLIC float linphone_call_stats_update_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call); -LINPHONE_PUBLIC float linphone_call_stats_update_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call); -LINPHONE_PUBLIC uint64_t linphone_call_stats_update_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats); +LINPHONE_PUBLIC float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats); +LINPHONE_PUBLIC float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call); +LINPHONE_PUBLIC float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call); +LINPHONE_PUBLIC uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call); /** Callback prototype */ typedef void (*LinphoneCallCbFunc)(LinphoneCall *call,void * user_data); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 6b272d962..e9a21389c 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1878,95 +1878,21 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getUploadBandwidt } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderLossRate(JNIEnv *env, jobject thiz, jlong stats_ptr) { const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; - const report_block_t *srb = NULL; - - if (!stats || !stats->sent_rtcp) - return (jfloat)0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->sent_rtcp->b_cont != NULL) - msgpullup(stats->sent_rtcp, -1); - if (rtcp_is_SR(stats->sent_rtcp)) - srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); - else if (rtcp_is_RR(stats->sent_rtcp)) - srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); - if (!srb) - return (jfloat)0.0; - return (jfloat)(100.0 * report_block_get_fraction_lost(srb) / 256.0); + return (jfloat) linphone_call_stats_get_sender_loss_rate(stats); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverLossRate(JNIEnv *env, jobject thiz, jlong stats_ptr) { const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; - const report_block_t *rrb = NULL; - - if (!stats || !stats->received_rtcp) - return (jfloat)0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->received_rtcp->b_cont != NULL) - msgpullup(stats->received_rtcp, -1); - if (rtcp_is_RR(stats->received_rtcp)) - rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); - else if (rtcp_is_SR(stats->received_rtcp)) - rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); - if (!rrb) - return (jfloat)0.0; - return (jfloat)(100.0 * report_block_get_fraction_lost(rrb) / 256.0); + return (jfloat) linphone_call_stats_get_receiver_loss_rate(stats); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) { LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; LinphoneCall *call = (LinphoneCall *)call_ptr; - const LinphoneCallParams *params; - const PayloadType *pt; - const report_block_t *srb = NULL; - - if (!stats || !call || !stats->sent_rtcp) - return (jfloat)0.0; - params = linphone_call_get_current_params(call); - if (!params) - return (jfloat)0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->sent_rtcp->b_cont != NULL) - msgpullup(stats->sent_rtcp, -1); - if (rtcp_is_SR(stats->sent_rtcp)) - srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); - else if (rtcp_is_RR(stats->sent_rtcp)) - srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); - if (!srb) - return (jfloat)0.0; - if (stats->type == LINPHONE_CALL_STATS_AUDIO) - pt = linphone_call_params_get_used_audio_codec(params); - else - pt = linphone_call_params_get_used_video_codec(params); - if (!pt || (pt->clock_rate == 0)) - return (jfloat)0.0; - return (jfloat)((float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate); + return (jfloat) linphone_call_stats_get_sender_interarrival_jitter(stats, call); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) { LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; LinphoneCall *call = (LinphoneCall *)call_ptr; - const LinphoneCallParams *params; - const PayloadType *pt; - const report_block_t *rrb = NULL; - - if (!stats || !call || !stats->received_rtcp) - return (jfloat)0.0; - params = linphone_call_get_current_params(call); - if (!params) - return (jfloat)0.0; - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */ - if (stats->received_rtcp->b_cont != NULL) - msgpullup(stats->received_rtcp, -1); - if (rtcp_is_SR(stats->received_rtcp)) - rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); - else if (rtcp_is_RR(stats->received_rtcp)) - rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); - if (!rrb) - return (jfloat)0.0; - if (stats->type == LINPHONE_CALL_STATS_AUDIO) - pt = linphone_call_params_get_used_audio_codec(params); - else - pt = linphone_call_params_get_used_video_codec(params); - if (!pt || (pt->clock_rate == 0)) - return (jfloat)0.0; - return (jfloat)((float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate); + return (jfloat) linphone_call_stats_get_receiver_interarrival_jitter(stats, call); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getRoundTripDelay(JNIEnv *env, jobject thiz, jlong stats_ptr) { return (jfloat)((LinphoneCallStats *)stats_ptr)->round_trip_delay; @@ -1974,18 +1900,7 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getRoundTripDelay extern "C" jlong Java_org_linphone_core_LinphoneCallStatsImpl_getLatePacketsCumulativeNumber(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) { LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr; LinphoneCall *call = (LinphoneCall *)call_ptr; - rtp_stats_t rtp_stats; - - if (!stats || !call) - return (jlong)0; - memset(&rtp_stats, 0, sizeof(rtp_stats)); - if (stats->type == LINPHONE_CALL_STATS_AUDIO) - audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats); -#ifdef VIDEO_ENABLED - else - video_stream_get_local_rtp_stats(call->videostream, &rtp_stats); -#endif - return (jlong)rtp_stats.outoftime; + return (jlong) linphone_call_stats_get_late_packets_cumulative_number(stats, call); } extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getJitterBufferSize(JNIEnv *env, jobject thiz, jlong stats_ptr) { return (jfloat)((LinphoneCallStats *)stats_ptr)->jitter_stats.jitter_buffer_size_ms; From 3c47f01e84effc08357a2510a791b506ed443042 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 5 Feb 2014 15:00:27 +0100 Subject: [PATCH 175/439] add flexisip test suite --- mediastreamer2 | 2 +- tester/Makefile.am | 5 +- tester/call_tester.c | 110 +------ tester/eventapi_tester.c | 15 +- tester/flexisip.conf | 10 +- tester/flexisip_tester.c | 574 ++++++++++++++++++++++++++++++++++++ tester/liblinphone_tester.c | 14 +- tester/liblinphone_tester.h | 13 +- tester/local_tester_hosts | 1 + tester/marie_rc | 8 +- tester/message_tester.c | 15 +- tester/pauline_rc | 8 +- tester/pauline_rc_tcp | 47 +++ tester/presence_tester.c | 6 +- tester/register_tester.c | 2 +- tester/setup_tester.c | 6 +- tester/upnp_tester.c | 6 +- 17 files changed, 704 insertions(+), 138 deletions(-) create mode 100644 tester/flexisip_tester.c create mode 100644 tester/local_tester_hosts create mode 100644 tester/pauline_rc_tcp diff --git a/mediastreamer2 b/mediastreamer2 index e2ea92a34..bba5dff9e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e2ea92a34d2577910115e20574f3f1e6474850da +Subproject commit bba5dff9ea4d4b6bc84d6b9b1e17469a3f8e6869 diff --git a/tester/Makefile.am b/tester/Makefile.am index ba8432bfa..4012b83e2 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -1,5 +1,5 @@ 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 + pauline_rc pauline_wild_rc pauline_rc_tcp tester_hosts sounds images certificates if BUILD_CUNIT_TESTS @@ -13,7 +13,8 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ call_tester.c \ presence_tester.c \ upnp_tester.c \ - eventapi_tester.c + eventapi_tester.c \ + flexisip_tester.c #liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) diff --git a/tester/call_tester.c b/tester/call_tester.c index f0fd07461..c47add6c2 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1,10 +1,10 @@ /* - belle-sip - SIP (RFC3261) library. - Copyright (C) 2010 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + 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, @@ -16,6 +16,7 @@ along with this program. If not, see . */ + #include #include "CUnit/Basic.h" #include "linphonecore.h" @@ -95,13 +96,18 @@ static void linphone_call_cb(LinphoneCall *call,void * user_data) { } #endif -static void check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) { +void liblinphone_tester_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); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + if (!c1 || !c2) return; 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 @@ -214,7 +220,7 @@ static void simple_call(void) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); CU_ASSERT_TRUE(call(pauline,marie)); - check_rtcp(marie,pauline); + liblinphone_tester_check_rtcp(marie,pauline); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -527,7 +533,7 @@ 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); + liblinphone_tester_check_rtcp(marie,pauline); /*then close the call*/ @@ -765,7 +771,7 @@ 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); + liblinphone_tester_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)); @@ -782,11 +788,11 @@ static void call_with_media_relay(void) { 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); + liblinphone_tester_check_rtcp(pauline,marie); #ifdef VIDEO_ENABLED CU_ASSERT_TRUE(add_video(pauline,marie)); - check_rtcp(pauline,marie); + liblinphone_tester_check_rtcp(pauline,marie); #endif /*just to sleep*/ @@ -1004,7 +1010,7 @@ static void srtp_ice_call(void) { add_video(pauline,marie); CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); - check_rtcp(marie,pauline); + liblinphone_tester_check_rtcp(marie,pauline); /*wait for ice to found the direct path*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); #endif @@ -1050,89 +1056,6 @@ 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; - char ringbackpath[256]; - snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); - - pol.automatically_accept=1; - pol.automatically_initiate=1; - - linphone_core_set_user_agent(marie1->lc,"Natted Linphone",NULL); - linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); - linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); - - linphone_core_enable_video(pauline->lc,TRUE,TRUE); - - linphone_core_enable_video(marie1->lc,TRUE,TRUE); - linphone_core_set_video_policy(marie1->lc,&pol); - /*use playfile for marie1 to avoid locking on capture card*/ - linphone_core_use_files (marie1->lc,TRUE); - linphone_core_set_play_file(marie1->lc,ringbackpath); - - linphone_core_enable_video(marie2->lc,TRUE,TRUE); - linphone_core_set_video_policy(marie2->lc,&pol); - linphone_core_set_audio_port_range(marie2->lc,40200,40300); - linphone_core_set_video_port_range(marie2->lc,40400,40500); - /*use playfile for marie2 to avoid locking on capture card*/ - linphone_core_use_files (marie2->lc,TRUE); - linphone_core_set_play_file(marie2->lc,ringbackpath); - - - lcs=ms_list_append(lcs,marie1->lc); - lcs=ms_list_append(lcs,marie2->lc); - lcs=ms_list_append(lcs,pauline->lc); - - linphone_call_params_enable_early_media_sending(params,TRUE); - linphone_call_params_enable_video(params,TRUE); - - linphone_core_invite_address_with_params(pauline->lc,marie1->identity,params); - linphone_call_params_destroy(params); - - CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,1000)); - - pauline_call=linphone_core_get_current_call(pauline->lc); - marie1_call=linphone_core_get_current_call(marie1->lc); - marie2_call=linphone_core_get_current_call(marie2->lc); - - /*wait a bit that streams are established*/ - wait_for_list(lcs,&dummy,1,3000); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>70); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70); - - linphone_core_accept_call(marie1->lc,linphone_core_get_current_call(marie1->lc)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); - - /*marie2 should get her call terminated*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); - - /*wait a bit that streams are established*/ - wait_for_list(lcs,&dummy,1,1000); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); - CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); - - linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,1000)); - - ms_list_free(lcs); - linphone_core_manager_destroy(marie1); - linphone_core_manager_destroy(marie2); - linphone_core_manager_destroy(pauline); -} static void simple_call_transfer(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -1539,7 +1462,6 @@ 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/eventapi_tester.c b/tester/eventapi_tester.c index 9cff70f9d..72b8c4fb6 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -1,10 +1,10 @@ /* - belle-sip - SIP (RFC3261) library. - Copyright (C) 2010 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + 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, @@ -16,6 +16,7 @@ along with this program. If not, see . */ + #include #include "CUnit/Basic.h" #include "linphonecore.h" @@ -28,6 +29,14 @@ static const char *subscribe_content="blabla"; static const char *notify_content="blabla"; +const char *liblinphone_tester_get_subscribe_content(void){ + return subscribe_content; +} + +const char *liblinphone_tester_get_notify_content(void){ + return notify_content; +} + void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){ CU_ASSERT_PTR_NOT_NULL_FATAL(content); CU_ASSERT_TRUE(strcmp(notify_content,(const char*)content->data)==0); diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 571d90731..fc8bdaea9 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -259,7 +259,7 @@ stateful=true # Fork invites to late registers # Default value: false -fork-late=false +fork-late=true # Only forward one response of forked invite to the caller # Default value: true @@ -272,7 +272,7 @@ fork-no-global-decline=false # Maximum duration for delivering a message (text) # Default value: 3600 -message-delivery-timeout=3600 +message-delivery-timeout=60 ## ## The Registrar module accepts REGISTERs for domains it manages, ## and store the address of record in order to route other requests @@ -301,12 +301,12 @@ 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 +# Default value: +sip.instance +#unique-id-parameters= # Maximum expire time for a REGISTER, in seconds. # Default value: 86400 -max-expires=86400 +max-expires=60 # Minimum expire time for a REGISTER, in seconds. # Default value: 60 diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c new file mode 100644 index 000000000..1ba25506d --- /dev/null +++ b/tester/flexisip_tester.c @@ -0,0 +1,574 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" + +static void subscribe_forking(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneContent content={0}; + LinphoneEvent *lev; + int expires= 600; + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,pauline2->lc); + + content.type="application"; + content.subtype="somexml"; + content.data=(char*)liblinphone_tester_get_subscribe_content(); + content.size=strlen(liblinphone_tester_get_subscribe_content()); + + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,&content); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline2->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->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)); + + linphone_event_terminate(lev); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(pauline2); + ms_list_free(lcs); +} + +static void message_forking(void) { + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + 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"); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie2->lc); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,1000)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); + ms_free(to); + ms_list_free(lcs); +} + +static void message_forking_with_unreachable_recipients(void) { + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + 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"); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + /*marie2 and marie3 go offline*/ + linphone_core_set_network_reachable(marie2->lc,FALSE); + linphone_core_set_network_reachable(marie3->lc,FALSE); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,1000)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + CU_ASSERT_TRUE( marie2->stat.number_of_LinphoneMessageReceived==0); + CU_ASSERT_TRUE( marie3->stat.number_of_LinphoneMessageReceived==0); + /*marie 2 goes online */ + linphone_core_set_network_reachable(marie2->lc,TRUE); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,1000)); + + /*wait a long time so that all transactions are expired*/ + wait_for_list(lcs,NULL,0,32000); + + /*marie 3 goes online now*/ + linphone_core_set_network_reachable(marie3->lc,TRUE); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneMessageReceived,1,1000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); + ms_free(to); + ms_list_free(lcs); +} + +static void message_forking_with_all_recipients_unreachable(void) { + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,marie->lc); + 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"); + + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + /*All marie's device go offline*/ + linphone_core_set_network_reachable(marie->lc,FALSE); + linphone_core_set_network_reachable(marie2->lc,FALSE); + linphone_core_set_network_reachable(marie3->lc,FALSE); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageInProgress,1,1000)); + /*flexisip will accept the message with 202 after 16 seconds*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,18000)); + CU_ASSERT_TRUE( marie->stat.number_of_LinphoneMessageReceived==0); + CU_ASSERT_TRUE( marie2->stat.number_of_LinphoneMessageReceived==0); + CU_ASSERT_TRUE( marie3->stat.number_of_LinphoneMessageReceived==0); + + /*marie 1 goes online */ + linphone_core_set_network_reachable(marie->lc,TRUE); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,1000)); + + /*marie 2 goes online */ + linphone_core_set_network_reachable(marie2->lc,TRUE); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,1000)); + + /*wait a long time so that all transactions are expired*/ + wait_for_list(lcs,NULL,0,32000); + + /*marie 3 goes online now*/ + linphone_core_set_network_reachable(marie3->lc,TRUE); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneMessageReceived,1,1000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); + ms_free(to); + ms_list_free(lcs); +} + +static void call_forking(void){ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + /*all devices from Marie should be ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*marie accepts the call on its first device*/ + linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*other devices should stop ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void call_forking_with_urgent_reply(void){ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + CU_ASSERT_TRUE(linphone_core_media_encryption_supported(pauline->lc,LinphoneMediaEncryptionSRTP)); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_network_reachable(marie2->lc,FALSE); + linphone_core_set_network_reachable(marie3->lc,FALSE); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback, after 5 seconds, when it will retry without SRTP*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,6000)); + /*Marie should be ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*marie accepts the call on its first device*/ + linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void call_forking_cancelled(void){ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); + /*all devices from Marie should be ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*pauline finally cancels the call*/ + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + + /*all devices should stop ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void call_forking_declined(bool_t declined_globaly){ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); + /*all devices from Marie should be ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*marie1 finally declines the call*/ + linphone_core_decline_call(marie->lc,linphone_core_get_current_call(marie->lc), + declined_globaly ? LinphoneReasonDeclined : LinphoneReasonBusy + ); + + if (declined_globaly){ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + /*all devices should stop ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + }else{ + /*pauline should continue ringing and be able to hear a call taken by marie2 */ + linphone_core_accept_call(marie2->lc, linphone_core_get_current_call(marie2->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + liblinphone_tester_check_rtcp(pauline,marie2); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + linphone_core_terminate_call(marie2->lc,linphone_core_get_current_call(marie2->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + } + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + +static void call_forking_declined_globaly(void){ + call_forking_declined(TRUE); +} + +static void call_forking_declined_localy(void){ + call_forking_declined(FALSE); +} + +static void call_forking_with_push_notification_single(void){ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + + /*unfortunately marie gets unreachable due to crappy 3G operator or iOS bug...*/ + linphone_core_set_network_reachable(marie->lc,FALSE); + + linphone_core_invite_address(pauline->lc,marie->identity); + + /*the server is expected to send a push notification to marie, this will wake up linphone, that will reconnect:*/ + linphone_core_set_network_reachable(marie->lc,TRUE); + + /*Marie shall receive the call immediately*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + /*pauline should hear ringback as well*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + /*marie accepts the call*/ + linphone_core_accept_call(marie->lc,linphone_core_get_current_call(marie->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + liblinphone_tester_check_rtcp(pauline,marie); + + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + ms_list_free(lcs); +} + +static void call_forking_with_push_notification_multiple(void){ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + /*unfortunately marie gets unreachable due to crappy 3G operator or iOS bug...*/ + linphone_core_set_network_reachable(marie2->lc,FALSE); + + linphone_core_invite_address(pauline->lc,marie->identity); + + /*marie1 will ring*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + /*pauline should hear ringback as well*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + /*the server is expected to send a push notification to marie2, this will wake up linphone, that will reconnect:*/ + linphone_core_set_network_reachable(marie2->lc,TRUE); + + /*Marie shall receive the call immediately*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*marie2 accepts the call*/ + linphone_core_accept_call(marie2->lc,linphone_core_get_current_call(marie2->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallConnected,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*call to marie1 should be cancelled*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + liblinphone_tester_check_rtcp(pauline,marie2); + + linphone_core_terminate_call(pauline->lc,linphone_core_get_current_call(pauline->lc)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); +} + +static void 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_tcp"); + MSList *lcs=NULL; + LinphoneCallParams *params=linphone_core_create_default_call_parameters(pauline->lc); + LinphoneVideoPolicy pol; + LinphoneCall *marie1_call; + LinphoneCall *marie2_call; + LinphoneCall *pauline_call; + int dummy=0; + char ringbackpath[256]; + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); + + pol.automatically_accept=1; + pol.automatically_initiate=1; + + linphone_core_set_user_agent(marie1->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_enable_video(pauline->lc,TRUE,TRUE); + + linphone_core_enable_video(marie1->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie1->lc,&pol); + /*use playfile for marie1 to avoid locking on capture card*/ + linphone_core_use_files (marie1->lc,TRUE); + linphone_core_set_play_file(marie1->lc,ringbackpath); + + linphone_core_enable_video(marie2->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie2->lc,&pol); + linphone_core_set_audio_port_range(marie2->lc,40200,40300); + linphone_core_set_video_port_range(marie2->lc,40400,40500); + /*use playfile for marie2 to avoid locking on capture card*/ + linphone_core_use_files (marie2->lc,TRUE); + linphone_core_set_play_file(marie2->lc,ringbackpath); + + + lcs=ms_list_append(lcs,marie1->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,pauline->lc); + + linphone_call_params_enable_early_media_sending(params,TRUE); + linphone_call_params_enable_video(params,TRUE); + + linphone_core_invite_address_with_params(pauline->lc,marie1->identity,params); + linphone_call_params_destroy(params); + + CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,1000)); + + pauline_call=linphone_core_get_current_call(pauline->lc); + marie1_call=linphone_core_get_current_call(marie1->lc); + marie2_call=linphone_core_get_current_call(marie2->lc); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,3000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70); + + linphone_core_accept_call(marie1->lc,linphone_core_get_current_call(marie1->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*marie2 should get her call terminated*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,1000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); + + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,1000)); + + ms_list_free(lcs); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); +} + + +test_t flexisip_tests[] = { + { "Subscribe forking", subscribe_forking }, + { "Message forking", message_forking }, + { "Message forking with unreachable recipients", message_forking_with_unreachable_recipients }, + { "Message forking with all recipients unreachable", message_forking_with_all_recipients_unreachable}, + { "Call forking", call_forking }, + { "Call forking cancelled", call_forking_cancelled }, + { "Call forking declined globaly", call_forking_declined_globaly }, + { "Call forking declined localy", call_forking_declined_localy }, + { "Call forking with urgent reply", call_forking_with_urgent_reply }, + { "Call forking with push notification (single)", call_forking_with_push_notification_single }, + { "Call forking with push notification (multiple)", call_forking_with_push_notification_multiple }, + { "Early-media call forking", early_media_call_forking }, +}; + + +test_suite_t flexisip_test_suite = { + "Flexisip", + NULL, + NULL, + sizeof(flexisip_tests) / sizeof(flexisip_tests[0]), + flexisip_tests +}; + + diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 8a889157a..67a0416c1 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -1,10 +1,10 @@ /* - belle-sip - SIP (RFC3261) library. - Copyright (C) 2010 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + 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, @@ -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" @@ -321,6 +322,7 @@ void liblinphone_tester_init(void) { add_test_suite(&upnp_test_suite); #endif add_test_suite(&event_test_suite); + add_test_suite(&flexisip_test_suite); } void liblinphone_tester_uninit(void) { @@ -423,6 +425,7 @@ void helper(const char *name) { "\t\t\t--auth-domain \n" "\t\t\t--suite \n" "\t\t\t--test \n" + "\t\t\t--dns-hosts \n" #if HAVE_CU_CURSES "\t\t\t--curses\n" #endif @@ -468,7 +471,10 @@ int main (int argc, char *argv[]) { } 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){ + }else if (strcmp(argv[i],"--dns-hosts")==0){ + CHECK_ARG("--dns-hosts", ++i, argc); + userhostsfile=argv[i]; + }else if (strcmp(argv[i],"--suite")==0){ CHECK_ARG("--suite", ++i, argc); suite_name=argv[i]; } else if (strcmp(argv[i],"--list-suites")==0){ diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index ac5302458..ec8d2b6dc 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -1,10 +1,10 @@ /* - belle-sip - SIP (RFC3261) library. - Copyright (C) 2010 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + 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, @@ -16,6 +16,7 @@ along with this program. If not, see . */ + #ifndef LIBLINPHONE_TESTER_H_ #define LIBLINPHONE_TESTER_H_ @@ -52,6 +53,7 @@ extern test_suite_t message_test_suite; extern test_suite_t presence_test_suite; extern test_suite_t upnp_test_suite; extern test_suite_t event_test_suite; +extern test_suite_t flexisip_test_suite; extern int liblinphone_tester_nb_test_suites(void); @@ -62,7 +64,6 @@ 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 @@ -210,6 +211,10 @@ bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int va bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); stats * get_stats(LinphoneCore *lc); LinphoneCoreManager *get_manager(LinphoneCore *lc); +const char *liblinphone_tester_get_subscribe_content(void); +const char *liblinphone_tester_get_notify_content(void); +void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); +void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee); #endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/local_tester_hosts b/tester/local_tester_hosts new file mode 100644 index 000000000..de1edc48c --- /dev/null +++ b/tester/local_tester_hosts @@ -0,0 +1 @@ +127.0.0.1 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org diff --git a/tester/marie_rc b/tester/marie_rc index a8365e91e..7b7645800 100644 --- a/tester/marie_rc +++ b/tester/marie_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 @@ -45,4 +45,4 @@ automatically_accept=0 device=StaticImage: Static picture [sound] -echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file +echocancellation=0 #to not overload cpu in case of VG diff --git a/tester/message_tester.c b/tester/message_tester.c index ef0901c93..66c75df86 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -1,10 +1,10 @@ /* - belle-sip - SIP (RFC3261) library. - Copyright (C) 2010 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + 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, @@ -16,6 +16,7 @@ along with this program. If not, see . */ + #include #include "CUnit/Basic.h" #include "linphonecore.h" @@ -53,7 +54,7 @@ void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { } } -void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { +void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { LinphoneCore* lc=(LinphoneCore*)ud; stats* counters = get_stats(lc); ms_message("Message [%s] [%s]",linphone_chat_message_get_text(msg),linphone_chat_message_state_to_string(state)); @@ -158,7 +159,7 @@ static void text_message_with_ack(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_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_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); @@ -173,7 +174,7 @@ static void text_message_with_external_body(void) { LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); linphone_chat_message_set_external_body_url(message,message_external_body_url="http://www.linphone.org"); - linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_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)); @@ -192,7 +193,7 @@ static void text_message_with_send_error(void) { 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); + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_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);*/ diff --git a/tester/pauline_rc b/tester/pauline_rc index 4d01058fe..09669b72c 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -1,7 +1,7 @@ [sip] -sip_port=5072 -sip_tcp_port=5072 -sip_tls_port=5073 +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 @@ -44,4 +44,4 @@ automatically_accept=0 device=StaticImage: Static picture [sound] -echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file +echocancellation=0 #to not overload cpu in case of VG diff --git a/tester/pauline_rc_tcp b/tester/pauline_rc_tcp new file mode 100644 index 000000000..809c1ace6 --- /dev/null +++ b/tester/pauline_rc_tcp @@ -0,0 +1,47 @@ +[sip] +sip_port=-1 +sip_tcp_port=-1 +sip_tls_port=-1 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +composing_idle_timeout=1 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tcp +reg_route=sip2.linphone.org;transport=tcp +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +#[friend_0] +#url="Mariette" +#pol=accept +#subscribe=0 + +[rtp] +audio_rtp_port=8090 +video_rtp_port=9092 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG diff --git a/tester/presence_tester.c b/tester/presence_tester.c index 9f3f009f1..cb1adc23c 100644 --- a/tester/presence_tester.c +++ b/tester/presence_tester.c @@ -1,10 +1,10 @@ /* - belle-sip - SIP (RFC3261) library. - Copyright (C) 2010 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + 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, diff --git a/tester/register_tester.c b/tester/register_tester.c index 6e5c929a5..51c092a51 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -4,7 +4,7 @@ This program is free software: you can 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 + 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, diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 7a5bac9c9..1b854baba 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -1,10 +1,10 @@ /* - belle-sip - SIP (RFC3261) library. - Copyright (C) 2010 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + 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, diff --git a/tester/upnp_tester.c b/tester/upnp_tester.c index 8b1d13e1d..04b5b865b 100644 --- a/tester/upnp_tester.c +++ b/tester/upnp_tester.c @@ -1,10 +1,10 @@ /* - belle-sip - SIP (RFC3261) library. - Copyright (C) 2010 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or + 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, From 77d09e7cff89af8faf42b38db4d15d963c348d6a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 5 Feb 2014 15:51:40 +0100 Subject: [PATCH 176/439] fix flexisip config file --- tester/flexisip.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tester/flexisip.conf b/tester/flexisip.conf index fc8bdaea9..a5cac58fc 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -261,6 +261,9 @@ stateful=true # Default value: false fork-late=true +call-fork-timeout=20 + + # Only forward one response of forked invite to the caller # Default value: true fork-one-response=true From 1817c82f7cd91b090f915e775e2a6ff83dd514e1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 5 Feb 2014 15:51:30 +0100 Subject: [PATCH 177/439] Removed useless code + updated ms2 with new opensles sound card --- build/android/Android.mk | 3 --- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 5 ----- mediastreamer2 | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index 8dfe0cb84..8c64fae8a 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -105,9 +105,6 @@ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../externals/libxml2/include \ $(LOCAL_PATH)/../../externals/build/libxml2 -ifeq ($(BUILD_OPENSLES_SOUNDCARD),1) - LOCAL_LDLIBS += -lOpenSLES -endif LOCAL_LDLIBS += -llog -ldl LOCAL_STATIC_LIBRARIES := \ diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 521a3d6b1..8b1527b09 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -57,11 +57,6 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { loadOptionalLibrary("avcodec-linphone-arm"); } - // OPENSSL (cryptography) - // linphone suffix avoids collision with libs in /system/lib - loadOptionalLibrary("crypto-linphone-" + eabi); - loadOptionalLibrary("ssl-linphone-" + eabi); - // Secure RTP and key negotiation loadOptionalLibrary("srtp-" + eabi); loadOptionalLibrary("zrtpcpp-" + eabi); // GPLv3+ diff --git a/mediastreamer2 b/mediastreamer2 index bba5dff9e..509430ba0 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit bba5dff9ea4d4b6bc84d6b9b1e17469a3f8e6869 +Subproject commit 509430ba06b18bbfb7d2d820ad86c7dcdb22af99 From 623029a06cbebe4d8838b09aa183c75614ae8a5b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 5 Feb 2014 17:01:55 +0100 Subject: [PATCH 178/439] Updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 509430ba0..506022f1c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 509430ba06b18bbfb7d2d820ad86c7dcdb22af99 +Subproject commit 506022f1c1b6bea182fe8724558fd908ef4b08af From 4d7b91d05ac43b5ef85ef7a6ce61c2831cdfba3e Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 6 Feb 2014 10:43:51 +0100 Subject: [PATCH 179/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 506022f1c..268095f87 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 506022f1c1b6bea182fe8724558fd908ef4b08af +Subproject commit 268095f87635f257bb2b8817cdb57870e9db91db From 3da4777e96e9a74da6ddbb424cc13ef03c4b179b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 6 Feb 2014 14:24:51 +0100 Subject: [PATCH 180/439] Enable iLBC codec on X86 Android devices. --- build/android/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index 8c64fae8a..bd7208d9d 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -185,7 +185,7 @@ ifeq ($(BUILD_SRTP), 1) LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE) endif -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +ifneq ($(TARGET_ARCH_ABI),armeabi) LOCAL_CFLAGS += -DHAVE_ILBC=1 LOCAL_STATIC_LIBRARIES += libmsilbc endif From 5c7330b17f63e8d3e6f576a54681f175248a8653 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 6 Feb 2014 15:01:34 +0100 Subject: [PATCH 181/439] avoid 100 trying to reset op auth counters --- .cproject | 2 +- coreapi/bellesip_sal/sal_impl.c | 15 ++++++------- oRTP | 2 +- tester/call_tester.c | 37 ++++++++++++++++++++++----------- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/.cproject b/.cproject index 8a879f8a7..e109f8b5b 100644 --- a/.cproject +++ b/.cproject @@ -22,7 +22,7 @@ - + diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 1c2df0879..29f65c91b 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -146,12 +146,13 @@ void sal_process_authentication(SalOp *op) { if (is_within_dialog) { belle_sip_object_unref(new_request); } - if (op->auth_info) sal_auth_info_delete(op->auth_info); - if (auth_list){ - auth_event=(belle_sip_auth_event_t*)(auth_list->data); - op->auth_info=sal_auth_info_create(auth_event); - belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); - } + } + /*always store auth info, for case of wrong credential*/ + if (op->auth_info) sal_auth_info_delete(op->auth_info); + if (auth_list){ + auth_event=(belle_sip_auth_event_t*)(auth_list->data); + op->auth_info=sal_auth_info_create(auth_event); + belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy); } } @@ -345,7 +346,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info); break; } - if (response_code !=401 && response_code !=407 && response_code !=403) { + if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) { /*not an auth request*/ op->auth_requests=0; } diff --git a/oRTP b/oRTP index 38eccb648..b03acc0a3 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 38eccb648fa80274082fb1aa299edcd37004f1cf +Subproject commit b03acc0a37ee64a12e9854e2ea4b781a9412240d diff --git a/tester/call_tester.c b/tester/call_tester.c index c47add6c2..34279e8d4 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1410,41 +1410,53 @@ static void call_established_with_rejected_reinvite_with_error(void) { linphone_core_manager_destroy(pauline); } -static void call_rejected_because_wrong_credentials_with_params(const char* user_agent) { +static void call_rejected_because_wrong_credentials_with_params(const char* user_agent,bool_t enable_auth_req_cb) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneAuthInfo* good_auth_info=linphone_auth_info_clone((LinphoneAuthInfo*)(linphone_core_get_auth_info_list(marie->lc)->data)); LinphoneAuthInfo* wrong_auth_info=linphone_auth_info_clone(good_auth_info); + bool_t result=FALSE; + linphone_auth_info_set_passwd(wrong_auth_info,"passecretdutout"); + linphone_core_clear_all_auth_info(marie->lc); if (user_agent) { linphone_core_set_user_agent(marie->lc,user_agent,NULL); } - linphone_core_clear_all_auth_info(marie->lc); + if (!enable_auth_req_cb) { + marie->lc->vtable.auth_info_requested=NULL; + linphone_core_add_auth_info(marie->lc,wrong_auth_info); + } CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(marie->lc,marie->identity)); - CU_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_auth_info_requested,1)); - - linphone_auth_info_set_passwd(wrong_auth_info,"passecretdutout"); - - /*automatically re-inititae the call*/ - linphone_core_add_auth_info(marie->lc,wrong_auth_info); + result=wait_for(marie->lc,marie->lc,&marie->stat.number_of_auth_info_requested,1); + if (enable_auth_req_cb) { + CU_ASSERT_TRUE(result); + /*automatically re-inititae the call*/ + linphone_core_add_auth_info(marie->lc,wrong_auth_info); + } CU_ASSERT_TRUE(wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneCallError,1)); - CU_ASSERT_EQUAL(marie->stat.number_of_auth_info_requested,2); - + if (enable_auth_req_cb) { + CU_ASSERT_EQUAL(marie->stat.number_of_auth_info_requested,2); + } /*to make sure unregister will work*/ linphone_core_clear_all_auth_info(marie->lc); linphone_core_add_auth_info(marie->lc,good_auth_info); linphone_core_manager_destroy(marie); } + static void call_rejected_because_wrong_credentials() { - call_rejected_because_wrong_credentials_with_params(NULL); + call_rejected_because_wrong_credentials_with_params(NULL,TRUE); } static void call_rejected_without_403_because_wrong_credentials() { - call_rejected_because_wrong_credentials_with_params("tester-no-403"); + call_rejected_because_wrong_credentials_with_params("tester-no-403",TRUE); +} + +static void call_rejected_without_403_because_wrong_credentials_no_auth_req_cb() { + call_rejected_because_wrong_credentials_with_params("tester-no-403",FALSE); } #ifdef VIDEO_ENABLED @@ -1480,6 +1492,7 @@ test_t call_tests[] = { { "Call with privacy", call_with_privacy }, { "Call rejected because of wrong credential", call_rejected_because_wrong_credentials}, { "Call rejected without 403 because of wrong credential", call_rejected_without_403_because_wrong_credentials}, + { "Call rejected without 403 because of wrong credential and no auth req cb", call_rejected_without_403_because_wrong_credentials_no_auth_req_cb}, { "Simple conference", simple_conference }, { "Simple call transfer", simple_call_transfer }, { "Unattended call transfer", unattended_call_transfer }, From e708ccad51c60931dfea029cfe2aa50b7e9256ba Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 6 Feb 2014 17:26:33 +0100 Subject: [PATCH 182/439] custom header management improvement. It is now possible to set custom contact. Other custom headers passed to the sal override SIP headers that would created by default. --- coreapi/bellesip_sal/sal_op_impl.c | 30 ++++++++++++++++++++++-------- include/sal/sal.h | 4 ---- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 70072d1f5..4e2f0802f 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -205,16 +205,29 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { sal_op_send_request(op,request); } -static void add_headers(belle_sip_header_t *h, belle_sip_message_t *msg){ - if (belle_sip_message_get_header(msg,belle_sip_header_get_name(h))==NULL) - belle_sip_message_add_header(msg,h); +static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){ + + if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){ + belle_sip_header_contact_t* newct; + /*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/ + sal_op_set_contact(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h)); + newct = sal_op_create_contact(op); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct)); + return; + } + /*if a header already exists in the message, replace it*/ + belle_sip_message_set_header(msg,h); + } void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){ if (op->base.sent_custom_headers){ belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers; belle_sip_list_t *l=belle_sip_message_get_all_headers(ch); - belle_sip_list_for_each2(l,(void (*)(void *, void *))add_headers,msg); + belle_sip_list_t *elem; + for(elem=l;elem!=NULL;elem=elem->next){ + add_headers(op,(belle_sip_header_t*)elem->data,msg); + } belle_sip_list_free(l); } } @@ -227,6 +240,11 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req int result =-1; belle_sip_uri_t *next_hop_uri=NULL; + if (add_contact) { + contact = sal_op_create_contact(op); + belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); + } + _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) { @@ -276,10 +294,6 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); - if (add_contact) { - contact = sal_op_create_contact(op); - belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact)); - } if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { /*hmm just in case we already have authentication param in cache*/ diff --git a/include/sal/sal.h b/include/sal/sal.h index 1dfe813ba..47402719e 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -516,12 +516,8 @@ 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); From 16066bea7a90122505434794ce466891a00bde6a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 7 Feb 2014 11:21:35 +0100 Subject: [PATCH 183/439] remove useless code --- coreapi/linphonecore.c | 1 - coreapi/misc.c | 126 ----------------------------------------- coreapi/private.h | 5 +- mediastreamer2 | 2 +- 4 files changed, 2 insertions(+), 132 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3ca34e0ba..8ba4742e0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -588,7 +588,6 @@ static void sound_config_read(LinphoneCore *lc) linphone_core_set_ringback(lc,tmpbuf); linphone_core_set_play_file(lc,lp_config_get_string(lc->config,"sound","hold_music",PACKAGE_SOUND_DIR "/" HOLD_MUSIC)); - check_sound_device(lc); lc->sound_conf.latency=0; #ifndef __ios tmp=TRUE; diff --git a/coreapi/misc.c b/coreapi/misc.c index 5273ac35b..1ceb432a0 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -54,132 +54,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define pclose _pclose #endif -#if !defined(WIN32) - -static char lock_name[80]; -static char lock_set=0; -/* put a lock file in /tmp. this is called when linphone runs as a daemon*/ -int set_lock_file() -{ - FILE *lockfile; - - snprintf(lock_name,80,"/tmp/linphone.%i",getuid()); - lockfile=fopen(lock_name,"w"); - if (lockfile==NULL) - { - printf("Failed to create lock file.\n"); - return(-1); - } - fprintf(lockfile,"%i",getpid()); - fclose(lockfile); - lock_set=1; - return(0); -} - -/* looks if there is a lock file. If presents return its content (the pid of the already running linphone), if not found, returns -1*/ -int get_lock_file() -{ - int pid; - FILE *lockfile; - - snprintf(lock_name,80,"/tmp/linphone.%i",getuid()); - lockfile=fopen(lock_name,"r"); - if (lockfile==NULL) - return(-1); - if (fscanf(lockfile,"%i",&pid)!=1){ - ms_warning("Could not read pid in lock file."); - fclose(lockfile); - return -1; - } - fclose(lockfile); - return pid; -} - -/* remove the lock file if it was set*/ -int remove_lock_file() -{ - int err=0; - if (lock_set) - { - err=unlink(lock_name); - lock_set=0; - } - return(err); -} - -#endif - -char *int2str(int number) -{ - char *numstr=ms_malloc(10); - snprintf(numstr,10,"%i",number); - return numstr; -} - -void check_sound_device(LinphoneCore *lc) -{ -#ifdef _linux - int fd=0; - int len; - int a; - char *file=NULL; - char *i810_audio=NULL; - char *snd_pcm_oss=NULL; - char *snd_mixer_oss=NULL; - char *snd_pcm=NULL; - fd=open("/proc/modules",O_RDONLY); - - if (fd>0){ - /* read the entire /proc/modules file and check if sound conf seems correct */ - /*a=fstat(fd,&statbuf); - if (a<0) ms_warning("Can't stat /proc/modules:%s.",strerror(errno)); - len=statbuf.st_size; - if (len==0) ms_warning("/proc/modules has zero size!"); - */ - /***** fstat does not work on /proc/modules for unknown reason *****/ - len=6000; - file=ms_malloc(len+1); - a=read(fd,file,len); - if (avtable.display_warning(lc,_("You are currently using the i810_audio driver.\nThis driver is buggy and so does not work with Linphone.\nWe suggest that you replace it by its equivalent ALSA driver,\neither with packages from your distribution, or by downloading\nALSA drivers at http://www.alsa-project.org."));*/ - goto end; - } - snd_pcm=strstr(file,"snd-pcm"); - if (snd_pcm!=NULL){ - snd_pcm_oss=strstr(file,"snd-pcm-oss"); - snd_mixer_oss=strstr(file,"snd-mixer-oss"); - if (snd_pcm_oss==NULL){ - lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the pcm oss emulation module\nis missing and linphone needs it. Please execute\n'modprobe snd-pcm-oss' as root to load it.")); - } - if (snd_mixer_oss==NULL){ - lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the mixer oss emulation module\nis missing and linphone needs it. Please execute\n 'modprobe snd-mixer-oss' as root to load it.")); - } - } - }else { - - ms_warning("Could not open /proc/modules."); - } - /* now check general volume. Some user forget to rise it and then complain that linphone is - not working */ - /* but some other users complain that linphone should not change levels... - if (lc->sound_conf.sndcard!=NULL){ - a=snd_card_get_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL); - if (a<50){ - ms_warning("General level is quite low (%i). Linphone rises it up for you.",a); - snd_card_set_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL,80); - } - } - */ - end: - if (file!=NULL) ms_free(file); - if (fd>0) close(fd); -#endif -} #define UDP_HDR_SZ 8 #define RTP_HDR_SZ 12 diff --git a/coreapi/private.h b/coreapi/private.h index e16ed9c5c..e7f66d2b8 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -263,10 +263,7 @@ 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 default_port); -int set_lock_file(); -int get_lock_file(); -int remove_lock_file(); -void check_sound_device(LinphoneCore *lc); + void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result); bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); diff --git a/mediastreamer2 b/mediastreamer2 index 268095f87..311ff6a94 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 268095f87635f257bb2b8817cdb57870e9db91db +Subproject commit 311ff6a9400967684a6de2c840e5c6f4d0d132c4 From aa8b9b1d7ebf14e451be37e0e283ece5ac4f06e5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 7 Feb 2014 12:25:16 +0100 Subject: [PATCH 184/439] generate a dmg --- Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index 96ca6ee42..ff729400c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -202,6 +202,7 @@ Portfile-devel: $(top_srcdir)/scripts/Portfile-devel.tmpl dist MACAPPNAME=Linphone.app MACAPPZIP=$(PACKAGE)-$(VERSION).app.zip +MACAPPDMG=$(PACKAGE)-$(VERSION).dmg BUNDLEPREFIX=./ BUNDLEDIR=$(BUNDLEPREFIX)$(MACAPPNAME) @@ -220,6 +221,7 @@ bundle: cp -f $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig sed -e 's:@executable_path.*/::g' $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig > $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules cd $(BUNDLEDIR)/.. && rm -f $(MACAPPZIP) && zip -r $(MACAPPZIP) $(MACAPPNAME) && cd - + cd $(BUNDLEDIR)/.. && rm -f $(MAXAPPDMG) && hdiutil create $(MACAPPDMG) -srcfolder $(MACAPPNAME) -ov && cd - ### ### CLEAN From 6f6d0375ba489815a5433aa70fba94416c284cda Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 7 Feb 2014 14:28:32 +0100 Subject: [PATCH 185/439] Update oRTP --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index b03acc0a3..012c18ac1 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b03acc0a37ee64a12e9854e2ea4b781a9412240d +Subproject commit 012c18ac1cf9c1826ec680d55b4b751645da9e91 From 1c5111a355faffc87ea6ebd0ca088e6234525117 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 7 Feb 2014 14:29:11 +0100 Subject: [PATCH 186/439] Add basic STUN tests --- tester/Makefile.am | 3 +- tester/liblinphone_tester.c | 39 ++++++------ tester/liblinphone_tester.h | 15 ++--- tester/stun_rc | 2 + tester/stun_tester.c | 116 ++++++++++++++++++++++++++++++++++++ 5 files changed, 148 insertions(+), 27 deletions(-) create mode 100644 tester/stun_rc create mode 100644 tester/stun_tester.c diff --git a/tester/Makefile.am b/tester/Makefile.am index 4012b83e2..f1d5f1f8e 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -14,7 +14,8 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ presence_tester.c \ upnp_tester.c \ eventapi_tester.c \ - flexisip_tester.c + flexisip_tester.c \ + stun_tester.c #liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 67a0416c1..dc844e539 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -7,13 +7,13 @@ 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. + This program is distributed in the hope that 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include @@ -53,7 +53,7 @@ const char *userhostsfile = "tester_hosts"; #ifdef ANDROID extern void AndroidPrintf(FILE *stream, const char *fmt, ...); -#define fprintf(file, fmt, ...) AndroidPrintf(file, fmt, ##__VA_ARGS__) +#define fprintf(file, fmt, ...) AndroidPrintf(file, fmt, ##__VA_ARGS__) #endif @@ -94,14 +94,14 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* char rootcapath[256]={0}; char dnsuserhostspath[256]={0}; char nowebcampath[256]={0}; - + if (path==NULL) path="."; if (file){ sprintf(filepath, "%s/%s", path, file); CU_ASSERT_TRUE_FATAL(ortp_file_exist(filepath)==0); } - + lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); sal_enable_test_features(lc->sal,TRUE); @@ -182,7 +182,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f LinphoneProxyConfig* proxy; int proxy_count; int retry=0; - + mgr->v_table.registration_state_changed=registration_state_changed; mgr->v_table.auth_info_requested=auth_info_requested; mgr->v_table.call_state_changed=call_state_changed; @@ -211,7 +211,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f } 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)); @@ -277,7 +277,7 @@ static int test_suite_index(const char *suite_name) { 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++) { @@ -321,6 +321,7 @@ void liblinphone_tester_init(void) { #ifdef UPNP add_test_suite(&upnp_test_suite); #endif + add_test_suite(&stun_test_suite); add_test_suite(&event_test_suite); add_test_suite(&flexisip_test_suite); } @@ -444,7 +445,7 @@ int main (int argc, char *argv[]) { int ret; const char *suite_name=NULL; const char *test_name=NULL; - + liblinphone_tester_init(); for(i=1;iDeleteLocalRef(env,javaString); } -JNIEXPORT +JNIEXPORT JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject obj, jobjectArray stringArray) { int i, ret; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index ec8d2b6dc..b2987a408 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -7,13 +7,13 @@ 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. + This program is distributed in the hope that 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -54,6 +54,7 @@ extern test_suite_t presence_test_suite; extern test_suite_t upnp_test_suite; extern test_suite_t event_test_suite; extern test_suite_t flexisip_test_suite; +extern test_suite_t stun_test_suite; extern int liblinphone_tester_nb_test_suites(void); @@ -155,7 +156,7 @@ typedef struct _stats { int number_of_LinphonePresenceActivityWorking; int number_of_LinphonePresenceActivityWorship; const LinphonePresenceModel *last_received_presence; - + int number_of_inforeceived; LinphoneInfoMessage* last_received_info_message; diff --git a/tester/stun_rc b/tester/stun_rc new file mode 100644 index 000000000..954a83b6c --- /dev/null +++ b/tester/stun_rc @@ -0,0 +1,2 @@ + [net] + firewall_policy=2 diff --git a/tester/stun_tester.c b/tester/stun_tester.c new file mode 100644 index 000000000..b5757b547 --- /dev/null +++ b/tester/stun_tester.c @@ -0,0 +1,116 @@ +/* + belle-sip - SIP (RFC3261) library. + Copyright (C) 2014 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" +#include "ortp/stun.h" +#include "ortp/port.h" + + +static const char* stun_address = "stun.linphone.org"; + + +static int test_stun_encode( char*buffer, size_t len, bool_t expect_fail ) +{ + StunAtrString username; + StunAtrString password; + StunMessage req; + memset(&req, 0, sizeof(StunMessage)); + memset(&username,0,sizeof(username)); + memset(&password,0,sizeof(password)); + stunBuildReqSimple( &req, &username, TRUE , TRUE , 11); + len = stunEncodeMessage( &req, buffer, len, &password); + if (len<=0){ + if( expect_fail ) + ms_message("Fail to encode stun message (EXPECTED).\n"); + else + ms_error("Fail to encode stun message.\n"); + return -1; + } + return len; +} + + +static void linphone_stun_test_encode() +{ + char smallBuff[12]; + size_t smallLen = 12; + char bigBuff[STUN_MAX_MESSAGE_SIZE]; + size_t bigLen = STUN_MAX_MESSAGE_SIZE; + + size_t len = test_stun_encode(smallBuff, smallLen, TRUE); + CU_ASSERT(len == -1); + + len = test_stun_encode(bigBuff, bigLen, TRUE); + CU_ASSERT(len > 0); + ms_message("STUN message encoded in %d bytes", len); +} + + +static void linphone_stun_test_grab_ip() +{ + LinphoneCoreManager* lc_stun = linphone_core_manager_new2( "stun_rc", FALSE); + LinphoneCall dummy_call; + int ping_time; + int tmp=0; + + memset(&dummy_call, 0, sizeof(LinphoneCall)); + dummy_call.audio_port = 7078; + dummy_call.audio_port = 9078; + + linphone_core_set_stun_server(lc_stun->lc, stun_address); + CU_ASSERT_STRING_EQUAL(stun_address, linphone_core_get_stun_server(lc_stun->lc)); + + wait_for(lc_stun->lc,lc_stun->lc,&tmp,1); + + ping_time = linphone_core_run_stun_tests(lc_stun->lc, &dummy_call); + CU_ASSERT(ping_time != -1); + + ms_message("Round trip to STUN: %d ms", ping_time); + + CU_ASSERT( dummy_call.ac.addr[0] != '\0'); + CU_ASSERT( dummy_call.ac.port != 0); + CU_ASSERT( dummy_call.vc.addr[0] != '\0'); + CU_ASSERT( dummy_call.vc.port != 0); + + ms_message("STUN test result: local audio port maps to %s:%i", + dummy_call.ac.addr, + dummy_call.ac.port); + ms_message("STUN test result: local video port maps to %s:%i", + dummy_call.vc.addr, + dummy_call.vc.port); + + linphone_core_manager_destroy(lc_stun); +} + + +test_t stun_tests[] = { + { "Basic Stun test (Ping/public IP)", linphone_stun_test_grab_ip }, + { "STUN encode buffer protection", linphone_stun_test_encode }, +}; + +test_suite_t stun_test_suite = { + "Stun", + NULL, + NULL, + sizeof(stun_tests) / sizeof(stun_tests[0]), + stun_tests +}; From af18f7293b54c6714290b37c7a23751a605a1cc4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 7 Feb 2014 14:58:44 +0100 Subject: [PATCH 187/439] replace belle_aip_header_extension by belle_sip_header --- coreapi/bellesip_sal/sal_impl.c | 8 ++------ coreapi/bellesip_sal/sal_op_call.c | 9 ++++----- coreapi/bellesip_sal/sal_op_call_transfer.c | 2 +- coreapi/bellesip_sal/sal_op_impl.c | 2 +- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 29f65c91b..30e69012d 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -786,7 +786,7 @@ SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, msg=(belle_sip_message_t*)belle_sip_request_new(); belle_sip_object_ref(msg); } - h=BELLE_SIP_HEADER(belle_sip_header_extension_parse(tmp)); + h=belle_sip_header_parse(tmp); ms_free(tmp); if (h==NULL){ belle_sip_error("Fail to parse extension header."); @@ -801,11 +801,7 @@ const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name); if (h){ - if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_extension_t)){ - return belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(h)); - }else{ - return belle_sip_header_get_unparsed_value(h); - } + return belle_sip_header_get_unparsed_value(h); } } return NULL; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 0aaec0512..7fe5982c7 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -44,7 +44,7 @@ static void call_set_error(SalOp* op,belle_sip_response_t* response){ 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))); + reason = ms_strdup_printf("%s %s",reason,belle_sip_header_get_unparsed_value(reason_header)); } sal_compute_sal_errors_from_code(code,&error,&sr); op->base.root->callbacks.call_failure(op,error,sr,reason,code); @@ -424,7 +424,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t process_sdp_for_invite(op,req); if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { - if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) { + if( strstr(belle_sip_header_get_unparsed_value(call_info),"answer-after=") != NULL) { op->auto_answer_asked=TRUE; ms_message("The caller asked to automatically answer the call(Emergency?)\n"); } @@ -662,9 +662,8 @@ int sal_call_notify_ringing(SalOp *op, bool_t early_media){ if (require) tags=belle_sip_header_get_unparsed_value(require); /* if client requires 100rel, then add necessary stuff*/ if (tags && strstr(tags,"100rel")!=0) { - - belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("Require","100rel"))); - belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("RSeq","1"))); + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("Require","100rel")); + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("RSeq","1")); } #ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 0fad03e83..796966acd 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -223,7 +223,7 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even ms_message("Receiving NOTIFY request on op [%p]",op); if (header_event - && strncasecmp(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(header_event)),"refer",strlen("refer"))==0 + && strncasecmp(belle_sip_header_get_unparsed_value(header_event),"refer",strlen("refer"))==0 && content_type && strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0 && strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0 diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 4e2f0802f..cade07854 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -462,7 +462,7 @@ bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,S ,reason_size ,"%s %s" ,belle_sip_response_get_reason_phrase(response) - ,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header))); + ,belle_sip_header_get_unparsed_value(reason_header)); } else { strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size); } From a4cf7471dff88fb268924b15bcef088fb13d3bd3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 7 Feb 2014 15:01:22 +0100 Subject: [PATCH 188/439] fix compilation issue on macosx --- oRTP | 2 +- tester/stun_tester.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/oRTP b/oRTP index 012c18ac1..b03acc0a3 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 012c18ac1cf9c1826ec680d55b4b751645da9e91 +Subproject commit b03acc0a37ee64a12e9854e2ea4b781a9412240d diff --git a/tester/stun_tester.c b/tester/stun_tester.c index b5757b547..0fa91dac5 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -61,7 +61,7 @@ static void linphone_stun_test_encode() len = test_stun_encode(bigBuff, bigLen, TRUE); CU_ASSERT(len > 0); - ms_message("STUN message encoded in %d bytes", len); + ms_message("STUN message encoded in %zu bytes", len); } From f2c903670f58f540a0f225f78d48d989d4d2f627 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 7 Feb 2014 16:24:12 +0100 Subject: [PATCH 189/439] Update oRTP --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index b03acc0a3..a5d9704f7 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b03acc0a37ee64a12e9854e2ea4b781a9412240d +Subproject commit a5d9704f7739057424b344240196fab64a0e6283 From 76df537f05885f537798ae481694d15546bf8887 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 7 Feb 2014 16:39:00 +0100 Subject: [PATCH 190/439] Update oRTP --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index a5d9704f7..1bfe38b8d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit a5d9704f7739057424b344240196fab64a0e6283 +Subproject commit 1bfe38b8d81917833b76b0019c512df8daa13e9f From a60d181babec1e1a47f45b36c52b7464c29f3180 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 7 Feb 2014 17:04:27 +0100 Subject: [PATCH 191/439] Update oRTP --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 1bfe38b8d..7d8332c42 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 1bfe38b8d81917833b76b0019c512df8daa13e9f +Subproject commit 7d8332c421537f6707fcca5ca89dbf4a30a04162 From a96c06657267e8edf1977c4931b2255e2a22d9a2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 7 Feb 2014 18:44:39 +0100 Subject: [PATCH 192/439] re-enable test "TLS with non tls server" (works with lastest belle-sip) --- coreapi/bellesip_sal/sal_impl.c | 7 +++++++ include/sal/sal.h | 2 ++ tester/register_tester.c | 6 +++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 30e69012d..dce0bb184 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -722,6 +722,13 @@ void sal_set_dns_timeout(Sal* sal,int timeout) { int sal_get_dns_timeout(const Sal* sal) { return belle_sip_stack_get_dns_timeout(sal->stack); } + +void sal_set_transport_timeout(Sal* sal,int timeout) { + belle_sip_stack_set_transport_timeout(sal->stack, timeout); +} +int sal_get_transport_timeout(const Sal* sal) { + return belle_sip_stack_get_transport_timeout(sal->stack); +} void sal_enable_dns_srv(Sal *sal, bool_t enable) { belle_sip_stack_enable_dns_srv(sal->stack, (unsigned char)enable); } diff --git a/include/sal/sal.h b/include/sal/sal.h index 47402719e..5c93786a9 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -683,6 +683,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_set_transport_timeout(Sal* sal,int timeout); +LINPHONE_PUBLIC int sal_get_transport_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); diff --git a/tester/register_tester.c b/tester/register_tester.c index 51c092a51..b090c9d1b 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -573,6 +573,7 @@ static void tls_certificate_failure(){ linphone_core_destroy(mgr->lc); } +/*the purpose of this test is to check that will not block the proxy config during SSL handshake for entire life in case of mistaken configuration*/ static void tls_with_non_tls_server(){ LinphoneCoreManager *mgr; LinphoneProxyConfig* proxy_cfg; @@ -582,6 +583,7 @@ static void tls_with_non_tls_server(){ mgr=linphone_core_manager_new2( "marie_rc", 0); lc=mgr->lc; + sal_set_transport_timeout(lc->sal,3000); linphone_core_get_default_proxy(lc,&proxy_cfg); linphone_proxy_config_edit(proxy_cfg); addr=linphone_address_new(linphone_proxy_config_get_addr(proxy_cfg)); @@ -590,9 +592,7 @@ 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)); - */ + CU_ASSERT_TRUE(wait_for_until(lc,lc,&mgr->stat.number_of_LinphoneRegistrationFailed,1,5000)); linphone_core_manager_destroy(mgr); } From ac61eee159f87637a5d9d0aaef8968b7c327fd62 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 7 Feb 2014 18:49:28 +0100 Subject: [PATCH 193/439] update ms2 to fix compilation errors --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 311ff6a94..3209fd2d7 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 311ff6a9400967684a6de2c840e5c6f4d0d132c4 +Subproject commit 3209fd2d7d87cfa4efbadc9efb045bbffd49dd6a From a4204d00796a8c885ee62c3ae828a5b7a529af99 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 8 Feb 2014 10:10:25 +0100 Subject: [PATCH 194/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3209fd2d7..98fcecc0b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3209fd2d7d87cfa4efbadc9efb045bbffd49dd6a +Subproject commit 98fcecc0b7f6893cb1f8a3068d95e1a6ad755487 From a23048a65f901b85e527e185690996e6e9566be5 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 10 Feb 2014 11:24:11 +0100 Subject: [PATCH 195/439] Fix missing QVGA resolution on iPhone --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8ba4742e0..b6f096363 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5121,7 +5121,7 @@ static MSVideoSizeDef supported_resolutions[]={ { { MS_VIDEO_SIZE_IOS_MEDIUM_H, MS_VIDEO_SIZE_IOS_MEDIUM_W } , "ios-medium" }, #endif { { MS_VIDEO_SIZE_CIF_W, MS_VIDEO_SIZE_CIF_H } , "cif" }, -#if !TARGET_OS_MAC +#if !TARGET_OS_MAC || TARGET_OS_IPHONE /* OS_MAC is 1 for iPhone, but we need QVGA */ { { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" }, #endif { { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" }, From 9fc721e71c08e314adfdd5d5ae18f20a80ee9478 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 10 Feb 2014 12:07:43 +0100 Subject: [PATCH 196/439] fixes and cleanup --- coreapi/linphonecall.c | 69 ++++++++++++++++++++++-------------------- coreapi/linphonecore.c | 22 ++++++++------ coreapi/linphonecore.h | 6 ++++ coreapi/misc.c | 4 --- tester/call_tester.c | 2 +- 5 files changed, 56 insertions(+), 47 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 8511375ad..cdf6920c4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1751,6 +1751,23 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna audio_stream_mixed_record_open(call->audiostream,call->params.record_file); call->current_params.record_file=ms_strdup(call->params.record_file); } + /* valid local tags are > 0 */ + if (stream->proto == SalProtoRtpSavp) { + local_st_desc=sal_media_description_find_stream(call->localdesc,SalProtoRtpSavp,SalAudio); + crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); + + if (crypto_idx >= 0) { + audio_stream_enable_srtp( + call->audiostream, + stream->crypto[0].algo, + local_st_desc->crypto[crypto_idx].master_key, + stream->crypto[0].master_key); + call->audiostream_encrypted=TRUE; + } else { + ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); + call->audiostream_encrypted=FALSE; + } + }else call->audiostream_encrypted=FALSE; audio_stream_start_full( call->audiostream, call->audio_profile, @@ -1779,23 +1796,6 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna } audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); - /* valid local tags are > 0 */ - if (stream->proto == SalProtoRtpSavp) { - local_st_desc=sal_media_description_find_stream(call->localdesc,SalProtoRtpSavp,SalAudio); - crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); - - if (crypto_idx >= 0) { - audio_stream_enable_srtp( - call->audiostream, - stream->crypto[0].algo, - local_st_desc->crypto[crypto_idx].master_key, - stream->crypto[0].master_key); - call->audiostream_encrypted=TRUE; - } else { - ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); - call->audiostream_encrypted=FALSE; - } - }else call->audiostream_encrypted=FALSE; if (call->params.in_conference){ /*transform the graph to connect it to the conference filter */ mute=stream->dir==SalStreamRecvOnly; @@ -1811,6 +1811,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; int used_pt=-1; + /* look for savp stream first */ const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpSavp,SalVideo); @@ -1831,6 +1832,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) { const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr; + const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,vstream->proto,SalVideo); + call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt); if (used_pt!=-1){ VideoStreamDir dir=VideoStreamSendRecv; @@ -1852,7 +1855,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna video_stream_use_preview_video_window (call->videostream,lc->use_preview_window); if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){ - cam=get_nowebcam_device(); + if (local_st_desc->dir==SalStreamSendOnly){ + /* localdesc stream dir to SendOnly is when we want to put on hold, so use nowebcam in this case*/ + cam=get_nowebcam_device(); + } dir=VideoStreamSendOnly; }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){ dir=VideoStreamRecvOnly; @@ -1872,6 +1878,18 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna cam=get_nowebcam_device(); } if (!is_inactive){ + if (vstream->proto == SalProtoRtpSavp) { + video_stream_enable_strp( + call->videostream, + vstream->crypto[0].algo, + local_st_desc->crypto[0].master_key, + vstream->crypto[0].master_key + ); + call->videostream_encrypted=TRUE; + }else{ + call->videostream_encrypted=FALSE; + } + call->log->video_enabled = TRUE; video_stream_set_direction (call->videostream, dir); ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation); @@ -1883,21 +1901,6 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna used_pt, linphone_core_get_video_jittcomp(lc), cam); video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool); } - - if (vstream->proto == SalProtoRtpSavp) { - const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc, - SalProtoRtpSavp,SalVideo); - - video_stream_enable_strp( - call->videostream, - vstream->crypto[0].algo, - local_st_desc->crypto[0].master_key, - vstream->crypto[0].master_key - ); - call->videostream_encrypted=TRUE; - }else{ - call->videostream_encrypted=FALSE; - } }else ms_warning("No video stream accepted."); }else{ ms_warning("No valid video stream defined."); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b6f096363..d9eb057e6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1263,14 +1263,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(lc,&payload_type_telephone_event,101,"0-15"); linphone_core_assign_payload_type(lc,&payload_type_g722,9,NULL); -#if defined(ANDROID) || defined (__IPHONE_OS_VERSION_MIN_REQUIRED) - /*shorten the DNS lookup time and send more retransmissions on mobiles: - - to workaround potential packet losses - - to avoid hanging for 30 seconds when the network doesn't work despite the phone thinks it does. - */ - _linphone_core_configure_resolver(); -#endif - #ifdef ENABLE_NONSTANDARD_GSM { PayloadType *pt; @@ -1340,7 +1332,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta net_config_read(lc); rtp_config_read(lc); codecs_config_read(lc); - sip_config_read(lc); /* this will start eXosip*/ + sip_config_read(lc); video_config_read(lc); //autoreplier_config_init(&lc->autoreplier_conf); lc->presence_model=linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL); @@ -6149,6 +6141,18 @@ void linphone_core_set_srtp_enabled(LinphoneCore *lc, bool_t enabled) { lp_config_set_int(lc->config,"sip","srtp",(int)enabled); } +const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){ + switch(menc){ + case LinphoneMediaEncryptionSRTP: + return "LinphoneMediaEncryptionSRTP"; + case LinphoneMediaEncryptionZRTP: + return "LinphoneMediaEncryptionZRTP"; + case LinphoneMediaEncryptionNone: + return "LinphoneMediaEncryptionNone"; + } + return "INVALID"; +} + /** * Returns whether a media encryption scheme is supported by the LinphoneCore engine **/ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b71118dd3..fe3dc043c 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -316,6 +316,12 @@ enum _LinphoneMediaEncryption { **/ typedef enum _LinphoneMediaEncryption LinphoneMediaEncryption; +/** + * Convert enum member to string. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc); + /*public: */ LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl); LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl); diff --git a/coreapi/misc.c b/coreapi/misc.c index 1ceb432a0..3a93bf97e 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1093,10 +1093,6 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ return 0; } - -void _linphone_core_configure_resolver(){ -} - SalReason linphone_reason_to_sal(LinphoneReason reason){ switch(reason){ case LinphoneReasonNone: diff --git a/tester/call_tester.c b/tester/call_tester.c index 34279e8d4..f32d41b02 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -945,7 +945,7 @@ static void encrypted_call(LinphoneMediaEncryption mode) { 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"); + ms_warning ("Not tested because %s not available", linphone_media_encryption_to_string(mode)); } linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); From a89206aec1c772b0e757f13012829d11a041488e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 10 Feb 2014 15:54:23 +0100 Subject: [PATCH 197/439] update oRTP --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 7d8332c42..07da4a398 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 7d8332c421537f6707fcca5ca89dbf4a30a04162 +Subproject commit 07da4a398549cba93b1627c5c3ca8626565ea884 From 227742469faaf239462ac0678d163f8aaff4305b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 10 Feb 2014 16:05:11 +0100 Subject: [PATCH 198/439] Splitted linphone_core_init in half into linphone_core_start, added new global state GlobalConfiguring and a new callback for the configuring state --- README | 2 +- coreapi/linphonecore.c | 65 +++++++++++++++---- coreapi/linphonecore.h | 31 ++++++++- coreapi/linphonecore_jni.cc | 21 ++++++ gtk/main.c | 8 +++ .../org/linphone/core/LinphoneCore.java | 44 +++++++++++++ 6 files changed, 155 insertions(+), 16 deletions(-) diff --git a/README b/README index f4d3f6053..0e913479e 100644 --- a/README +++ b/README @@ -33,7 +33,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. Here is the command line to get these dependencies installed for Ubuntu && Debian - $ sudo apt-get install libtool intltool libgtk2.0-dev libosip2-dev libexosip2-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libxv-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev libxml2-dev + $ sudo apt-get install libtool intltool libgtk2.0-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libxv-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev libxml2-dev + for optional library $ sudo apt-get install libreadline-dev libgsm1-dev libtheora-dev libsoup2.4-dev libsqlite3-dev libupnp4-dev diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d9eb057e6..6b8a79661 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -68,6 +68,7 @@ static void linphone_core_run_hooks(LinphoneCore *lc); static void linphone_core_free_hooks(LinphoneCore *lc); #include "enum.h" +#include "contact_providers_priv.h" const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); @@ -610,6 +611,17 @@ static void sound_config_read(LinphoneCore *lc) linphone_core_get_audio_features(lc); } +static void certificates_config_read(LinphoneCore *lc) +{ +#ifdef __linux + sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs")); +#else + sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE)); +#endif + linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); + linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); +} + static void sip_config_read(LinphoneCore *lc) { char *contact; @@ -635,14 +647,7 @@ 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); - -#ifdef __linux - sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs")); -#else - sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE)); -#endif - linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); - linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); + certificates_config_read(lc); /*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/ sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc)); /*start listening on ports*/ @@ -1221,7 +1226,7 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const } } -static void misc_config_read (LinphoneCore *lc) { +static void misc_config_read(LinphoneCore *lc) { LpConfig *config=lc->config; const char *uuid; @@ -1237,10 +1242,30 @@ static void misc_config_read (LinphoneCore *lc) { sal_set_uuid(lc->sal, uuid); } +static void linphone_core_start(LinphoneCore * lc) { + sip_setup_register_all(); + sound_config_read(lc); + net_config_read(lc); + rtp_config_read(lc); + codecs_config_read(lc); + sip_config_read(lc); + video_config_read(lc); + //autoreplier_config_init(&lc->autoreplier_conf); + lc->presence_model=linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL); + misc_config_read(lc); + ui_config_read(lc); +#ifdef TUNNEL_ENABLED + lc->tunnel=linphone_core_tunnel_new(lc); + if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); +#endif + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Ready")); + lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; + linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); +} - -static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, 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)); @@ -1344,9 +1369,19 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta #endif if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Ready")); - lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; - linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); + lc->vtable.display_status(lc, _("Configuring")); + linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); + + const char *remote_provisioning_uri = lp_config_get_string(lc->config, "app", "remote_provisioning", NULL); + LinphoneConfiguringState configuring_result = LinphoneConfiguringSkipped; + if (remote_provisioning_uri) { + certificates_config_read(lc); + } + + if (lc->vtable.configuring_status) + lc->vtable.configuring_status(lc, configuring_result, configuring_result == LinphoneConfiguringFailed ? _("Configuring failed") : NULL); + + linphone_core_start(lc); } /** @@ -5923,6 +5958,8 @@ const char *linphone_global_state_to_string(LinphoneGlobalState gs){ break; case LinphoneGlobalShutdown: return "LinphoneGlobalShutdown"; + case LinphoneGlobalConfiguring: + return "LinphoneGlobalConfiguring"; break; } return NULL; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index fe3dc043c..c7d05d017 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1062,7 +1062,8 @@ typedef enum _LinphoneGlobalState{ LinphoneGlobalOff, LinphoneGlobalStartup, LinphoneGlobalOn, - LinphoneGlobalShutdown + LinphoneGlobalShutdown, + LinphoneGlobalConfiguring }LinphoneGlobalState; const char *linphone_global_state_to_string(LinphoneGlobalState gs); @@ -1212,6 +1213,23 @@ typedef void (*LinphoneCoreCallStatsUpdatedCb)(LinphoneCore *lc, LinphoneCall *c */ typedef void (*LinphoneCoreInfoReceivedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); +/** + * LinphoneGlobalState describes the global state of the LinphoneCore object. + * It is notified via the LinphoneCoreVTable::global_state_changed +**/ +typedef enum _LinphoneConfiguringState { + LinphoneConfiguringSuccessful, + LinphoneConfiguringFailed, + LinphoneConfiguringSkipped +} LinphoneConfiguringState; + +/** + * Callback prototype for configuring status changes notification + * @param lc the LinphoneCore + * @param message informational message. + */ +typedef void (*LinphoneCoreConfiguringStatusCb)(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); + /** * This structure holds all callbacks that the application should implement. * None is mandatory. @@ -1236,6 +1254,7 @@ typedef struct _LinphoneCoreVTable{ LinphoneCoreSubscriptionStateChangedCb subscription_state_changed; /**NewGlobalRef(env->GetObjectClass( alistener)); @@ -276,6 +277,10 @@ public: subscriptionDirClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionDir")); subscriptionDirFromIntId = env->GetStaticMethodID(subscriptionDirClass,"fromInt","(I)Lorg/linphone/core/SubscriptionDir;"); + + configuringStateId = env->GetMethodID(listenerClass,"configuringStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;Ljava/lang/String;)V"); + configuringStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RemoteProvisioningState")); + configuringStateFromIntId = env->GetStaticMethodID(globalStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;"); } ~LinphoneCoreData() { @@ -286,6 +291,7 @@ public: if (userdata) env->DeleteGlobalRef(userdata); env->DeleteGlobalRef(listenerClass); env->DeleteGlobalRef(globalStateClass); + env->DeleteGlobalRef(configuringStateClass); env->DeleteGlobalRef(registrationStateClass); env->DeleteGlobalRef(callStateClass); env->DeleteGlobalRef(chatMessageStateClass); @@ -317,6 +323,10 @@ public: jmethodID subscriptionStateId; jmethodID publishStateId; jmethodID notifyRecvId; + + jclass configuringStateClass; + jmethodID configuringStateId; + jmethodID configuringStateFromIntId; jclass globalStateClass; jmethodID globalStateId; @@ -708,6 +718,17 @@ public: ,content ? create_java_linphone_content(env,content) : NULL ); } + + static void configuringStatus(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener, lcData->configuringStateId, lcData->core, env->CallStaticObjectMethod(lcData->configuringStateClass,lcData->configuringStateFromIntId,(jint)status), message ? env->NewStringUTF(message) : NULL); + } }; extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env diff --git a/gtk/main.c b/gtk/main.c index 49ff8542b..bb000296c 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -58,6 +58,7 @@ static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); static void linphone_gtk_display_status(LinphoneCore *lc, const char *status); +static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg); static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning); static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url); @@ -272,6 +273,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; vtable.transfer_state_changed=linphone_gtk_transfer_state_changed; vtable.dtmf_received=linphone_gtk_dtmf_received; + vtable.configuring_status=linphone_gtk_configuring_status; the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); @@ -1237,6 +1239,12 @@ static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){ status); } +static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + if (status == LinphoneConfiguringFailed) { + linphone_gtk_display_something(GTK_MESSAGE_ERROR, message); + } +} + static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){ linphone_gtk_display_something(GTK_MESSAGE_INFO,msg); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 50d109a9e..6c7094ddf 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -53,6 +53,10 @@ public interface LinphoneCore { * Shutdown */ static public GlobalState GlobalShutdown = new GlobalState(3,"GlobalShutdown"); + /** + * Configuring + */ + static public GlobalState GlobalConfiguring = new GlobalState(4,"GlobalConfiguring"); private final int mValue; private final String mStringValue; @@ -75,6 +79,46 @@ public interface LinphoneCore { return mStringValue; } } + /** + * linphone remote provisioning states + */ + static public class RemoteProvisioningState { + + static private Vector values = new Vector(); + /** + * Off + */ + static public RemoteProvisioningState ConfiguringSuccessful = new RemoteProvisioningState(0,"ConfiguringSuccessful"); + /** + * Startup + */ + static public RemoteProvisioningState ConfiguringFailed = new RemoteProvisioningState(1,"ConfiguringFailed"); + /** + * On + */ + static public RemoteProvisioningState ConfiguringSkipped = new RemoteProvisioningState(2,"ConfiguringSkipped"); + + private final int mValue; + private final String mStringValue; + + + private RemoteProvisioningState(int value,String stringValue) { + mValue = value; + values.addElement(this); + mStringValue=stringValue; + } + public static RemoteProvisioningState fromInt(int value) { + + for (int i=0; i Date: Mon, 10 Feb 2014 16:30:46 +0100 Subject: [PATCH 199/439] Fix typo in Android jni file --- 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 0c3e73e0e..3ac117faa 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -280,7 +280,7 @@ public: configuringStateId = env->GetMethodID(listenerClass,"configuringStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;Ljava/lang/String;)V"); configuringStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RemoteProvisioningState")); - configuringStateFromIntId = env->GetStaticMethodID(globalStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;"); + configuringStateFromIntId = env->GetStaticMethodID(configuringStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;"); } ~LinphoneCoreData() { From a6d0ce4b4c517b0ec03b2b94af77b3be5faedf4a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 10 Feb 2014 17:02:35 +0100 Subject: [PATCH 200/439] Fix infinity loop due to latest GlobalState introduced --- coreapi/private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/private.h b/coreapi/private.h index e7f66d2b8..a2264af68 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -706,7 +706,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit); -#define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup) +#define linphone_core_ready(lc) ((lc)->state==LinphoneGlobalOn || (lc)->state==LinphoneGlobalShutdown) void _linphone_core_configure_resolver(); struct _EcCalibrator{ From 6f1a5e21e5f34cb486444c0caa02a12a29325235 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 10 Feb 2014 17:17:41 +0100 Subject: [PATCH 201/439] Update ortp --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index 07da4a398..747129fc3 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 07da4a398549cba93b1627c5c3ca8626565ea884 +Subproject commit 747129fc30c79d0eb416217782da531ccf3cc71f From aacd7bb5a246de1b366f935d8947d1ca1df6f99b Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 10 Feb 2014 17:34:56 +0100 Subject: [PATCH 202/439] protect call tester add_video against crash when call has fail --- coreapi/bellesip_sal/sal_sdp.c | 2 +- tester/call_tester.c | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index dd7794b26..76d834dab 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -379,7 +379,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S ; mime_param_it=mime_param_it->next ) { mime_param=BELLE_SDP_MIME_PARAMETER ( mime_param_it->data ) - pt=payload_type_new(); + 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 ) ); diff --git a/tester/call_tester.c b/tester/call_tester.c index f32d41b02..5a64dab4e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -672,25 +672,25 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) 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); + if ((call_obj = linphone_core_get_current_call(callee->lc))) { + callee_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj)); + /*add video*/ + linphone_call_params_enable_video(callee_params,TRUE); + linphone_core_update_call(callee->lc,call_obj,callee_params); - 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(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); + 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); + } else return -1; } static void call_with_video_added(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); From 43258541231afcaab0de05bad259c4ace4b2ce11 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 11 Feb 2014 11:28:07 +0100 Subject: [PATCH 203/439] fix double notification of auth_info_requested() --- coreapi/callbacks.c | 8 +++++--- tester/register_tester.c | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index ab1f5a720..f22d35f20 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -727,10 +727,12 @@ static void auth_failure(SalOp *op, SalAuthInfo* info) { LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); if (ai){ ms_message("%s/%s/%s authentication fails.",info->realm,info->username,info->domain); + /*ask again for password if auth info was already supplied but apparently not working*/ + if (lc->vtable.auth_info_requested) { + lc->vtable.auth_info_requested(lc,info->realm,info->username,info->domain); + } } - if (lc->vtable.auth_info_requested) { - lc->vtable.auth_info_requested(lc,info->realm,info->username,info->domain); - } + } static void register_success(SalOp *op, bool_t registered){ diff --git a/tester/register_tester.c b/tester/register_tester.c index b090c9d1b..4705ba13f 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -304,7 +304,7 @@ static void authenticated_register_with_late_credentials(){ 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,2); /*1 registration error = 2 auth requested*/ + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); linphone_core_manager_destroy(mgr); } @@ -314,7 +314,7 @@ static void authenticated_register_with_wrong_late_credentials(){ LCSipTransports transport = {5070,5070,0,5071}; char route[256]; const char* saved_test_passwd=test_password; - char* wrong_passwd="mot de pass tout pourrit"; + char* wrong_passwd="mot de pass tout pourri"; test_password=wrong_passwd; @@ -324,7 +324,7 @@ static void authenticated_register_with_wrong_late_credentials(){ 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,3); + 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; From cdc528d126a449555c47ea389fab116d84ad2451 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 11 Feb 2014 11:47:49 +0100 Subject: [PATCH 204/439] fix liblinphone tester on android --- build/android/liblinphone_tester.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index 5d9c7a469..4e86e8867 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -8,7 +8,9 @@ common_SRC_FILES := \ register_tester.c \ setup_tester.c \ upnp_tester.c \ - eventapi_tester.c + eventapi_tester.c \ + stun_tester.c \ + flexisip_tester.c common_C_INCLUDES += \ $(LOCAL_PATH) \ From 289b814b784acc45330604235bcf3bc9ee23ee26 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 11 Feb 2014 14:36:06 +0100 Subject: [PATCH 205/439] Update MS2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 98fcecc0b..6b9335478 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 98fcecc0b7f6893cb1f8a3068d95e1a6ad755487 +Subproject commit 6b9335478b15863d37a41b9d36c28eae216b7990 From 8a230b2e864968d4c9ed28dfe5a08acd4e283115 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 11 Feb 2014 15:22:00 +0100 Subject: [PATCH 206/439] fix android liblinphone test compilation --- tester/call_tester.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 5a64dab4e..ecf0068bf 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -174,7 +174,7 @@ 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)) + if(!linphone_core_get_current_call(caller_mgr->lc) || !linphone_core_get_current_call(callee_mgr->lc) || !linphone_core_get_current_call_remote_address(callee_mgr->lc)) return 0; else { LinphoneAddress* callee_from=linphone_address_clone(caller_mgr->identity); @@ -690,7 +690,7 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) /*send vfu*/ linphone_call_send_vfu_request(call_obj); return wait_for(caller->lc,callee->lc,&callee->stat.number_of_IframeDecoded,initial_callee_stat.number_of_IframeDecoded+1); - } else return -1; + } else return 0; } static void call_with_video_added(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); From e42391c459d97f85738885931c9d5ece26a227ab Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 11 Feb 2014 15:45:42 +0100 Subject: [PATCH 207/439] Fix resources path on BlackBerry 10. --- configure.ac | 9 ++++++++- tester/liblinphone_tester.c | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fc5e5a52e..c12172764 100644 --- a/configure.ac +++ b/configure.ac @@ -491,7 +491,14 @@ if test "$relativeprefix" = "yes" ; then fi dnl Set PACKAGE_LOCALE_DIR in config.h. -DATADIRNAME=share +case "$target_os" in + *qnx*) + DATADIRNAME=app/native/assets + ;; + *) + DATADIRNAME=share + ;; +esac AC_DEFINE_UNQUOTED(PACKAGE_LOCALE_DIR, "${package_prefix}/${DATADIRNAME}/locale",[Defines the place where locales can be found]) AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${package_prefix}/${DATADIRNAME}",[Defines the place where data are found]) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index dc844e539..9f654542c 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -46,8 +46,12 @@ const char* test_route="sip2.linphone.org"; #if WINAPI_FAMILY_PHONE_APP const char *liblinphone_tester_file_prefix="Assets"; #else +#ifdef __QNX__ +const char *liblinphone_tester_file_prefix="./app/native/assets/"; +#else const char *liblinphone_tester_file_prefix="."; #endif +#endif const char *userhostsfile = "tester_hosts"; From 510440a148f09d089384a8e090aecdc5b5960f00 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 11 Feb 2014 15:46:58 +0100 Subject: [PATCH 208/439] Fix crashes on BlackBerry 10. --- coreapi/linphonecore.c | 2 +- tester/message_tester.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6b8a79661..e37d47c72 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1874,7 +1874,7 @@ static void apply_user_agent(LinphoneCore *lc){ 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); + snprintf(ua_string, sizeof(ua_string) - 1, "%s/%s", name?name:"", ver?ver:""); if (lc->sal) { sal_set_user_agent(lc->sal, ua_string); sal_append_stack_string_to_user_agent(lc->sal); diff --git a/tester/message_tester.c b/tester/message_tester.c index 66c75df86..cf99c1013 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -33,9 +33,11 @@ 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)); + const char *text=linphone_chat_message_get_text(message); + const char *external_body_url=linphone_chat_message_get_external_body_url(message); + ms_message("Message from [%s] is [%s] , external URL [%s]",from?from:"" + ,text?text:"" + ,external_body_url?external_body_url:""); ms_free(from); counters = get_stats(lc); counters->number_of_LinphoneMessageReceived++; From 2ba2aea601dffd73571c2d00f8b1f460c4b1878a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 11 Feb 2014 17:24:19 +0100 Subject: [PATCH 209/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6b9335478..42678c758 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6b9335478b15863d37a41b9d36c28eae216b7990 +Subproject commit 42678c7588aa090a9038a4845ed09e5a5f9a70d7 From 9ca78dd129aabf44fb8c48adba1be866bf794d7c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 11 Feb 2014 16:25:11 +0100 Subject: [PATCH 210/439] Moved lpc2xml and xml2lpc from tools to coreapi --- coreapi/Makefile.am | 4 +++- {tools => coreapi}/lpc2xml.c | 0 {tools => coreapi}/lpc2xml.h | 0 {tools => coreapi}/xml2lpc.c | 0 {tools => coreapi}/xml2lpc.h | 0 tools/Makefile.am | 29 ++--------------------------- 6 files changed, 5 insertions(+), 28 deletions(-) rename {tools => coreapi}/lpc2xml.c (100%) rename {tools => coreapi}/lpc2xml.h (100%) rename {tools => coreapi}/xml2lpc.c (100%) rename {tools => coreapi}/xml2lpc.h (100%) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 0d0775be7..e8b640c32 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -18,7 +18,7 @@ CLEANFILES=$(GITVERSION_FILE) ## Process this file with automake to produce Makefile.in linphone_includedir=$(includedir)/linphone -linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h +linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h xml2lpc.h lpc2xml.h if BUILD_TUNNEL linphone_include_HEADERS+=linphone_tunnel.h @@ -53,6 +53,8 @@ liblinphone_la_SOURCES=\ ldap/ldapprovider.c ldap/ldapprovider.h \ dict.c \ xml.c \ + xml2lpc.c \ + lpc2xml.c \ $(GITVERSION_FILE) if BUILD_UPNP diff --git a/tools/lpc2xml.c b/coreapi/lpc2xml.c similarity index 100% rename from tools/lpc2xml.c rename to coreapi/lpc2xml.c diff --git a/tools/lpc2xml.h b/coreapi/lpc2xml.h similarity index 100% rename from tools/lpc2xml.h rename to coreapi/lpc2xml.h diff --git a/tools/xml2lpc.c b/coreapi/xml2lpc.c similarity index 100% rename from tools/xml2lpc.c rename to coreapi/xml2lpc.c diff --git a/tools/xml2lpc.h b/coreapi/xml2lpc.h similarity index 100% rename from tools/xml2lpc.h rename to coreapi/xml2lpc.h diff --git a/tools/Makefile.am b/tools/Makefile.am index 5ef2535ad..d993aa591 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -18,29 +18,6 @@ EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc if BUILD_TOOLS -lib_LTLIBRARIES=libxml2lpc.la liblpc2xml.la - -libxml2lpc_la_SOURCES=\ - xml2lpc.c \ - xml2lpc.h - -liblpc2xml_la_SOURCES=\ - lpc2xml.c \ - lpc2xml.h - -libxml2lpc_la_CFLAGS=$(COMMON_CFLAGS) -libxml2lpc_la_LIBADD=\ - $(top_builddir)/coreapi/liblinphone.la \ - $(LIBXML2_LIBS) - -liblpc2xml_la_CFLAGS=$(COMMON_CFLAGS) -liblpc2xml_la_LIBADD=\ - $(top_builddir)/coreapi/liblinphone.la \ - $(LIBXML2_LIBS) - -libxml2lpc_la_LDFLAGS=-no-undefined -liblpc2xml_la_LDFLAGS=-no-undefined - bin_PROGRAMS=xml2lpc_test lpc2xml_test lp-gen-wrappers xml2lpc_test_SOURCES=\ @@ -51,13 +28,11 @@ lpc2xml_test_SOURCES=\ xml2lpc_test_CFLAGS=$(COMMON_CFLAGS) xml2lpc_test_LDADD=\ - $(top_builddir)/coreapi/liblinphone.la \ - libxml2lpc.la + $(top_builddir)/coreapi/liblinphone.la lpc2xml_test_CFLAGS=$(COMMON_CFLAGS) lpc2xml_test_LDADD=\ - $(top_builddir)/coreapi/liblinphone.la \ - liblpc2xml.la + $(top_builddir)/coreapi/liblinphone.la lp_gen_wrappers_SOURCES=genwrappers.cc \ software-desc.cc software-desc.hh \ From b43e8a71a2d4cbf78808d594deb853b5ae149001 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 11 Feb 2014 16:47:43 +0100 Subject: [PATCH 211/439] Fix android core listener missing new added callback for remote provisioning --- .../linphone/core/tutorials/TutorialBuddyStatus.java | 8 ++++++++ .../org/linphone/core/tutorials/TutorialChatRoom.java | 8 ++++++++ .../linphone/core/tutorials/TutorialHelloWorld.java | 8 ++++++++ .../linphone/core/tutorials/TutorialRegistration.java | 8 ++++++++ .../org/linphone/core/LinphoneCoreListener.java | 11 +++++++++++ 5 files changed, 43 insertions(+) diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index f7178b63c..c9ccb9105 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.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.LinphoneCore.RemoteProvisioningState; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; @@ -286,5 +287,12 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void configuringStatus(LinphoneCore lc, + RemoteProvisioningState state, String message) { + // 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 fc5e9dccc..e2dc10d34 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -29,6 +29,7 @@ import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.LinphoneCore.RemoteProvisioningState; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; @@ -210,5 +211,12 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa write("Remote has stop writing"); } + @Override + public void configuringStatus(LinphoneCore lc, + RemoteProvisioningState state, String message) { + // 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 e6761da97..e0faf9d92 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -26,6 +26,7 @@ import org.linphone.core.LinphoneChatRoom; import org.linphone.core.LinphoneContent; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; +import org.linphone.core.LinphoneCore.RemoteProvisioningState; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; @@ -212,5 +213,12 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } + @Override + public void configuringStatus(LinphoneCore lc, + RemoteProvisioningState state, String message) { + // 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 7e6d8a002..c3aebd307 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -26,6 +26,7 @@ import org.linphone.core.LinphoneChatRoom; import org.linphone.core.LinphoneContent; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.EcCalibratorStatus; +import org.linphone.core.LinphoneCore.RemoteProvisioningState; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListener; @@ -243,6 +244,13 @@ public class TutorialRegistration implements LinphoneCoreListener { } + @Override + public void configuringStatus(LinphoneCore lc, + RemoteProvisioningState state, String message) { + // TODO Auto-generated method stub + + } + } diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index d01fa01a7..5d2ac5f5f 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -18,6 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; +import org.linphone.core.LinphoneCore.RemoteProvisioningState; + /** * @@ -163,6 +165,15 @@ public interface LinphoneCoreListener { */ void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, PublishState state); + /** + * Notifies the changes about the remote provisioning step + * @param lc the LinphoneCore + * @param state the RemoteProvisioningState + * @param message the error message if state == Failed + */ + void configuringStatus(LinphoneCore lc, RemoteProvisioningState state, + String message); + /**< @Deprecated Notifies the application that it should show up * @return */ void show(LinphoneCore lc); From bfb6bd76d49e028b97a786cf4dcd63f55b94e3f0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 11 Feb 2014 16:55:58 +0100 Subject: [PATCH 212/439] Fix android build --- build/android/Android.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index bd7208d9d..f4601822a 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -206,9 +206,9 @@ ifeq ($(BUILD_SRTP),1) endif ifeq ($(BUILD_REMOTE_PROVISIONING),1) -LOCAL_SRC_FILES += ../tools/xml2lpc.c \ +LOCAL_SRC_FILES += ../coreapi/xml2lpc.c \ ../tools/xml2lpc_jni.cc \ - ../tools/lpc2xml.c \ + ../coreapi/lpc2xml.c \ ../tools/lpc2xml_jni.cc endif From ca272c15df692bb5fbaf4c6a242cd5ecaac47bb2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 11 Feb 2014 17:51:14 +0100 Subject: [PATCH 213/439] fix double initialization --- coreapi/linphonecore.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e37d47c72..de3db32fd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1352,22 +1352,6 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab lc->network_last_check = 0; lc->network_last_status = FALSE; - sip_setup_register_all(); - sound_config_read(lc); - net_config_read(lc); - rtp_config_read(lc); - codecs_config_read(lc); - sip_config_read(lc); - video_config_read(lc); - //autoreplier_config_init(&lc->autoreplier_conf); - lc->presence_model=linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL); - misc_config_read(lc); - ui_config_read(lc); -#ifdef TUNNEL_ENABLED - lc->tunnel=linphone_core_tunnel_new(lc); - if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); -#endif - if (lc->vtable.display_status) lc->vtable.display_status(lc, _("Configuring")); linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); @@ -1375,7 +1359,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab const char *remote_provisioning_uri = lp_config_get_string(lc->config, "app", "remote_provisioning", NULL); LinphoneConfiguringState configuring_result = LinphoneConfiguringSkipped; if (remote_provisioning_uri) { - certificates_config_read(lc); + certificates_config_read(lc); } if (lc->vtable.configuring_status) From ddfdb7f9ced0aa281cd8f11fb10f97efaff91945 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 11 Feb 2014 17:12:42 +0100 Subject: [PATCH 214/439] Added remote provisioning feature in liblinphone --- build/android/Android.mk | 4 +- coreapi/Makefile.am | 1 + coreapi/linphonecore.c | 16 ++-- coreapi/linphonecore.h | 4 +- coreapi/remote_provisioning.c | 140 ++++++++++++++++++++++++++++++++++ gtk/main.c | 4 +- 6 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 coreapi/remote_provisioning.c diff --git a/build/android/Android.mk b/build/android/Android.mk index f4601822a..bd59cb4e3 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -209,8 +209,8 @@ ifeq ($(BUILD_REMOTE_PROVISIONING),1) LOCAL_SRC_FILES += ../coreapi/xml2lpc.c \ ../tools/xml2lpc_jni.cc \ ../coreapi/lpc2xml.c \ - ../tools/lpc2xml_jni.cc - + ../tools/lpc2xml_jni.cc \ + ../coreapi/remote_provisioning.c endif ifeq ($(BUILD_SQLITE),1) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index e8b640c32..68d78447f 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -55,6 +55,7 @@ liblinphone_la_SOURCES=\ xml.c \ xml2lpc.c \ lpc2xml.c \ + remote_provisioning.c \ $(GITVERSION_FILE) if BUILD_UPNP diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index de3db32fd..5a9b834e6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1265,6 +1265,13 @@ static void linphone_core_start(LinphoneCore * lc) { linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); } +static void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) { + if (lc->vtable.configuring_status) + lc->vtable.configuring_status(lc, state, message); + + linphone_core_start(lc); +} + static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata) { ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); @@ -1357,15 +1364,12 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); const char *remote_provisioning_uri = lp_config_get_string(lc->config, "app", "remote_provisioning", NULL); - LinphoneConfiguringState configuring_result = LinphoneConfiguringSkipped; if (remote_provisioning_uri) { certificates_config_read(lc); + linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri, linphone_configuring_terminated); + } else { + linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); } - - if (lc->vtable.configuring_status) - lc->vtable.configuring_status(lc, configuring_result, configuring_result == LinphoneConfiguringFailed ? _("Configuring failed") : NULL); - - linphone_core_start(lc); } /** diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c7d05d017..e91d627ac 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2281,13 +2281,15 @@ typedef void (*ContactSearchCallback)( LinphoneContactSearch* id, MSList* friend /** Remote provisioning */ +typedef void (*ConfiguringCallback)(LinphoneCore *lc, LinphoneConfiguringState state, const char *message); + /** * Download a remote provisioning file from the given uri and applies it to current lp config. * A restart is requiered for the changes to be applied. * @param lc the LinphoneCore * @param remote_provisioning_uri the URI at which the remote provisioning file is available */ -LINPHONE_PUBLIC LinphoneConfiguringState linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri); +LINPHONE_PUBLIC void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri, ConfiguringCallback cb); #ifdef __cplusplus } diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c new file mode 100644 index 000000000..fe4269a66 --- /dev/null +++ b/coreapi/remote_provisioning.c @@ -0,0 +1,140 @@ +/* +remote_provisioning.c +Copyright (C) 2010 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "linphonecore.h" +#include "bellesip_sal/sal_impl.h" +#include "xml2lpc.h" + +#define XML2LPC_CALLBACK_BUFFER_SIZE 1024 + +static ConfiguringCallback linphone_callback = NULL; +static bool_t waiting_response = FALSE; + +static void xml2lpc_callback(void *ctx, xml2lpc_log_level level, const char *fmt, va_list list) { + char buffer[XML2LPC_CALLBACK_BUFFER_SIZE]; + vsnprintf(buffer, XML2LPC_CALLBACK_BUFFER_SIZE, fmt, list); + + if (level == XML2LPC_ERROR) + ms_error("%s", buffer); + else if (level == XML2LPC_WARNING) + ms_warning("%s", buffer); + /*else + ms_message("%s", buffer); // Don't log debug messages */ +} + +static void linphone_remote_provisioning_apply(LinphoneCore *lc, const char *xml) { + xml2lpc_context *context = xml2lpc_context_new(xml2lpc_callback, lc); + int result = xml2lpc_set_xml_string(context, xml); + if (result == 0) { + result = xml2lpc_convert(context, linphone_core_get_config(lc)); + if (result == 0) { + lp_config_sync(linphone_core_get_config(lc)); + xml2lpc_context_destroy(context); + if (linphone_callback) + linphone_callback(lc, LinphoneConfiguringSuccessful, NULL); + } else { + xml2lpc_context_destroy(context); + if (linphone_callback) + linphone_callback(lc, LinphoneConfiguringFailed, "convert failed"); + } + } else { + xml2lpc_context_destroy(context); + if (linphone_callback) + linphone_callback(lc, LinphoneConfiguringFailed, "set xml string failed"); + } +} + +static void belle_request_process_response_event(void *ctx, const belle_http_response_event_t *event) { + waiting_response = FALSE; + LinphoneCore *lc = (LinphoneCore *)ctx; + belle_sip_message_t *body = BELLE_SIP_MESSAGE(event->response); + const char *message = belle_sip_message_get_body(body); + + if (belle_http_response_get_status_code(event->response) == 200) { + linphone_remote_provisioning_apply(lc, message); + } else { + if (linphone_callback) + linphone_callback(lc, LinphoneConfiguringFailed, message); + } +} + +static void belle_request_process_io_error(void *ctx, const belle_sip_io_error_event_t *event) { + waiting_response = FALSE; + LinphoneCore *lc = (LinphoneCore *)ctx; + + if (linphone_callback) + linphone_callback(lc, LinphoneConfiguringFailed, "io error"); +} + +static void belle_request_process_timeout(void *ctx, const belle_sip_timeout_event_t *event) { + waiting_response = FALSE; + LinphoneCore *lc = (LinphoneCore *)ctx; + + if (linphone_callback) + linphone_callback(lc, LinphoneConfiguringFailed, "timeout"); +} + +static void belle_request_process_auth_requested(void *ctx, belle_sip_auth_event_t *event) { + waiting_response = FALSE; + LinphoneCore *lc = (LinphoneCore *)ctx; + + if (linphone_callback) + linphone_callback(lc, LinphoneConfiguringFailed, "auth requested"); +} + +static belle_http_request_listener_callbacks_t belle_request_listener = { + belle_request_process_response_event, + belle_request_process_io_error, + belle_request_process_timeout, + belle_request_process_auth_requested +}; + +static void linphone_remote_provisioning_download(LinphoneCore *lc, const char *remote_provisioning_uri) { + belle_sip_object_pool_t *pool = belle_sip_object_pool_push(); + belle_sip_stack_t *stack = belle_sip_stack_new(NULL); + + belle_http_request_listener_t *listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc); + belle_http_provider_t *provider = belle_sip_stack_create_http_provider(stack, "0.0.0.0"); + + belle_http_request_t *request = belle_http_request_create( + "GET", + belle_generic_uri_parse(remote_provisioning_uri), + NULL + ); + + belle_http_provider_send_request(provider, request, listener); + + waiting_response = TRUE; + while (waiting_response) { + belle_sip_stack_sleep(stack, 10); + } + + belle_sip_object_unref(pool); + belle_sip_object_unref(provider); + belle_sip_object_unref(stack); +} + +/** + * Fetches the remote provisioning from the given URI and tries to apply it to the current LpConfig + * @param lc the LinphoneCore + * @param remote_provisioning_uri the URI at which the provisioning is available + */ +void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri, ConfiguringCallback cb) { + linphone_callback = cb; + linphone_remote_provisioning_download(lc, remote_provisioning_uri); +} \ No newline at end of file diff --git a/gtk/main.c b/gtk/main.c index bb000296c..761342ee6 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1240,9 +1240,7 @@ static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){ } static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { - if (status == LinphoneConfiguringFailed) { - linphone_gtk_display_something(GTK_MESSAGE_ERROR, message); - } + } static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){ From 26687dc345c7cf6ef360f49832b620ef5b21c417 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 12 Feb 2014 14:10:39 +0100 Subject: [PATCH 215/439] Allow out-of-tree build. --- autogen.sh | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/autogen.sh b/autogen.sh index 3bb716755..cf357cd66 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,5 +1,11 @@ #!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +THEDIR=`pwd` +cd $srcdir + #AM_VERSION="1.10" if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then # automake-1.10 (recommended) is not available on Fedora 8 @@ -42,12 +48,17 @@ autoheader $AUTOMAKE --force-missing --add-missing --copy autoconf -if [ -x oRTP/autogen.sh ]; then - echo "Generating build scripts in oRTP..." - ( cd oRTP && ./autogen.sh ) +set +x +if [ "$srcdir" = "." ]; then + if [ -x oRTP/autogen.sh ]; then + echo "Generating build scripts in oRTP..." + ( cd oRTP && ./autogen.sh ) + fi + + if [ -x mediastreamer2/autogen.sh ]; then + echo "Generating build scripts in mediastreamer2..." + ( cd mediastreamer2 && ./autogen.sh ) + fi fi -if [ -x mediastreamer2/autogen.sh ]; then - echo "Generating build scripts in mediastreamer2..." - ( cd mediastreamer2 && ./autogen.sh ) -fi +cd $THEDIR From bddbdc7cd8913f3e3e6c13cace5010452900c890 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Feb 2014 14:25:34 +0100 Subject: [PATCH 216/439] provisioning in gtk app in progress --- coreapi/bellesip_sal/sal_impl.c | 5 +- gtk/Makefile.am | 4 +- gtk/config-fetching.c | 48 +++++++++++++ gtk/config-uri.ui | 99 ++++++++++++++++++++++++++ gtk/linphone.h | 1 + gtk/main.c | 121 +++++++++++++++++++++----------- gtk/main.ui | 10 +++ 7 files changed, 244 insertions(+), 44 deletions(-) create mode 100644 gtk/config-fetching.c create mode 100644 gtk/config-uri.ui diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index dce0bb184..70f04673c 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -140,7 +140,10 @@ void sal_process_authentication(SalOp *op) { } sal_remove_pending_auth(op->base.root,op); }else { - ms_message("No auth info found for [%s]",sal_op_get_from(op)); + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(response,belle_sip_header_from_t); + char *tmp=belle_sip_object_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); + ms_message("No auth info found for [%s]",tmp); + belle_sip_free(tmp); sal_add_pending_auth(op->base.root,op); if (is_within_dialog) { diff --git a/gtk/Makefile.am b/gtk/Makefile.am index f9240eb02..1d1be276f 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -12,7 +12,8 @@ UI_FILES= about.ui \ waiting.ui \ dscp_settings.ui \ call_statistics.ui \ - ldap.ui + ldap.ui \ + config-uri.ui PIXMAPS= \ stock_people.png @@ -49,6 +50,7 @@ linphone_SOURCES= \ loginframe.c \ singleinstance.c \ conference.c \ + config-fetching.c \ linphone.h if BUILD_WIZARD linphone_SOURCES+= \ diff --git a/gtk/config-fetching.c b/gtk/config-fetching.c new file mode 100644 index 000000000..b9ce5cb70 --- /dev/null +++ b/gtk/config-fetching.c @@ -0,0 +1,48 @@ +/* +linphone, gtk-glade interface. +Copyright (C) 2008 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "linphone.h" +#include "lpconfig.h" + + +void linphone_gtk_set_configuration_uri(GtkWidget *item){ + GtkWidget *w=linphone_gtk_create_window("config-uri"); + gtk_widget_show(w); +} + +void linphone_gtk_config_uri_changed(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); + const char *uri=gtk_entry_get_text(GTK_ENTRY(entry)); + if (uri){ + /*set provisionning uri to the core*/ + gtk_widget_destroy(w); + } + + if (uri){ + linphone_gtk_schedule_restart(); + gtk_main_quit(); + } +} + +void linphone_gtk_config_uri_cancel(GtkWidget *button){ + GtkWidget *w=gtk_widget_get_toplevel(button); + gtk_widget_destroy(w); +} + diff --git a/gtk/config-uri.ui b/gtk/config-uri.ui new file mode 100644 index 000000000..5e864743e --- /dev/null +++ b/gtk/config-uri.ui @@ -0,0 +1,99 @@ + + + + + + False + 5 + Specifying a remote configuration URI + dialog + + + True + False + 2 + + + True + False + end + + + gtk-undo + True + True + True + False + True + + + + False + False + 0 + + + + + gtk-ok + True + True + True + False + True + + + + False + False + 1 + + + + + False + True + end + 0 + + + + + True + False + This dialog allows to set an http or https address when configuration is to be fetched at startup. +Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. + True + 80 + + + True + True + 1 + + + + + True + True + + https:// + False + False + True + True + + + True + True + 2 + + + + + + button2 + button1 + + + diff --git a/gtk/linphone.h b/gtk/linphone.h index 024e6348a..8f996244c 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -165,3 +165,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_schedule_restart(void); \ No newline at end of file diff --git a/gtk/main.c b/gtk/main.c index 761342ee6..8cc3a2790 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -53,6 +53,7 @@ static LinphoneCore *the_core=NULL; static GtkWidget *the_ui=NULL; static LinphoneLDAPContactProvider* ldap_provider = NULL; +static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str); static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg); static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid); static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url); @@ -72,6 +73,7 @@ static gboolean linphone_gtk_auto_answer(LinphoneCall *call); void linphone_gtk_status_icon_set_blinking(gboolean val); void _linphone_gtk_enable_video(gboolean val); void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data); +static void linphone_gtk_init_ui(void); #ifndef HAVE_GTK_OSX static gint main_window_x=0; @@ -87,6 +89,7 @@ static char *progpath=NULL; gchar *linphone_logfile=NULL; static gboolean workaround_gtk_entry_chinese_bug=FALSE; static gchar *custom_config_file=NULL; +static gboolean restart=FALSE; static GOptionEntry linphone_options[]={ { @@ -250,11 +253,16 @@ void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap) : NULL; } +void linphone_gtk_schedule_restart(void){ + restart=TRUE; +} + static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file, const char *db_file) { LinphoneCoreVTable vtable={0}; gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE); + vtable.global_state_changed=linphone_gtk_global_state_changed; vtable.call_state_changed=linphone_gtk_call_state_changed; vtable.registration_state_changed=linphone_gtk_registration_state_changed; vtable.notify_presence_received=linphone_gtk_notify_recv; @@ -1352,6 +1360,16 @@ void linphone_gtk_notify(LinphoneCall *call, const char *msg){ } } +static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str){ + switch(state){ + case LinphoneGlobalOn: + if (the_core) linphone_gtk_init_ui(); + break; + default: + break; + } +} + static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){ if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){ LinphoneCore *lc=linphone_call_get_core(call); @@ -2044,23 +2062,29 @@ static void linphone_gtk_check_soundcards(){ } } +static void linphone_gtk_quit_core(void){ + linphone_gtk_unmonitor_usb(); + g_source_remove_by_user_data(linphone_gtk_get_core()); +#ifdef BUILD_WIZARD + linphone_gtk_close_assistant(); +#endif + linphone_gtk_set_ldap(NULL); + linphone_gtk_destroy_log_window(); + linphone_core_destroy(the_core); + linphone_gtk_log_uninit(); +} + static void linphone_gtk_quit(void){ static gboolean quit_done=FALSE; if (!quit_done){ quit_done=TRUE; - linphone_gtk_unmonitor_usb(); - g_source_remove_by_user_data(linphone_gtk_get_core()); -#ifdef BUILD_WIZARD - linphone_gtk_close_assistant(); -#endif - linphone_gtk_set_ldap(NULL); + linphone_gtk_quit_core(); linphone_gtk_uninit_instance(); - linphone_gtk_destroy_log_window(); - linphone_core_destroy(the_core); - linphone_gtk_log_uninit(); #ifdef HAVE_NOTIFY notify_uninit(); #endif + gtk_widget_destroy(the_ui); + the_ui=NULL; gdk_threads_leave(); } } @@ -2080,11 +2104,34 @@ static gboolean on_block_termination(void){ } #endif +static void linphone_gtk_init_ui(void){ + linphone_gtk_init_main_window(); + +#ifdef BUILD_WIZARD + // Veryfing if at least one sip account is configured. If not, show wizard + if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) { + linphone_gtk_show_assistant(); + } +#endif + +#ifndef HAVE_GTK_OSX + linphone_gtk_init_status_icon(); +#endif + if (!iconified){ + linphone_gtk_show_main_window(); + linphone_gtk_check_soundcards(); + } + if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0) + linphone_gtk_check_for_new_version(); + linphone_gtk_monitor_usb(); +} + int main(int argc, char *argv[]){ char *config_file; const char *factory_config_file; const char *lang; GtkSettings *settings; + const char *icon_path=LINPHONE_ICON; GdkPixbuf *pbuf; const char *app_name="Linphone"; LpConfig *factory; @@ -2188,14 +2235,11 @@ int main(int argc, char *argv[]){ factory=lp_config_new(NULL); lp_config_read_file(factory,factory_config_file); app_name=lp_config_get_string(factory,"GtkUi","title","Linphone"); + icon_path=lp_config_get_string(factory,"GtkUi","icon",LINPHONE_ICON); } - - if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){ - g_warning("Another running instance of linphone has been detected. It has been woken-up."); - g_warning("This instance is going to exit now."); - gdk_threads_leave(); - return 0; - } + g_set_application_name(app_name); + pbuf=create_pixbuf(icon_path); + if (pbuf!=NULL) gtk_window_set_default_icon(pbuf); add_pixmap_directory("pixmaps"); add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone"); @@ -2208,45 +2252,38 @@ int main(int argc, char *argv[]){ g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL); #endif +core_start: + if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){ + g_warning("Another running instance of linphone has been detected. It has been woken-up."); + g_warning("This instance is going to exit now."); + gdk_threads_leave(); + return 0; + } + the_ui=linphone_gtk_create_window("main"); g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE)); linphone_gtk_create_log_window(); linphone_core_enable_logs_with_cb(linphone_gtk_log_handler); - + db_file=linphone_gtk_message_storage_get_db_file(NULL); + linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file); - - g_set_application_name(app_name); - pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON)); - if (pbuf!=NULL) gtk_window_set_default_icon(pbuf); - + /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/ gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core()); - gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL); - linphone_gtk_init_main_window(); - -#ifdef BUILD_WIZARD - // Veryfing if at least one sip account is configured. If not, show wizard - if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) { - linphone_gtk_show_assistant(); - } -#endif - -#ifndef HAVE_GTK_OSX - linphone_gtk_init_status_icon(); -#endif - if (!iconified){ - linphone_gtk_show_main_window(); - linphone_gtk_check_soundcards(); - } - if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0) - linphone_gtk_check_for_new_version(); - linphone_gtk_monitor_usb(); + gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core()); + + if (linphone_core_get_global_state(the_core)==LinphoneGlobalOn) linphone_gtk_init_ui(); gtk_main(); linphone_gtk_quit(); + + if (restart){ + restart=FALSE; + goto core_start; + } #ifndef HAVE_GTK_OSX /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/ gtk_status_icon_set_visible(icon,FALSE); diff --git a/gtk/main.ui b/gtk/main.ui index 05461b6fc..96d3e11c0 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -858,6 +858,16 @@ + + + True + False + False + Set configuration URI + True + + + gtk-disconnect From 304361add5258aadf397032371e6d33003008388 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Mon, 3 Feb 2014 15:20:50 +0100 Subject: [PATCH 217/439] Remove trailing spaces on linphonec call with options --- console/commands.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/console/commands.c b/console/commands.c index ba2f1dc3c..981c0ac60 100644 --- a/console/commands.c +++ b/console/commands.c @@ -558,10 +558,12 @@ lpc_cmd_call(LinphoneCore *lc, char *args) opt2=strstr(args,"--early-media"); if (opt1){ opt1[0]='\0'; + while(--opt1 > args && opt1[0]==' ') opt1[0]='\0'; linphone_call_params_enable_video (cp,FALSE); } if (opt2){ opt2[0]='\0'; + while(--opt2 > args && opt2[0]==' ') opt2[0]='\0'; linphone_call_params_enable_early_media_sending(cp,TRUE); } if ( NULL == (call=linphone_core_invite_with_params(lc, args,cp)) ) From f021e9aa519ed263d180e1a3aed951e68dd0a62f Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Wed, 12 Feb 2014 14:00:27 +0100 Subject: [PATCH 218/439] Expose chat message response code and reason. --- coreapi/bellesip_sal/sal_op_message.c | 17 +++-------------- coreapi/callbacks.c | 14 +++++++++++++- coreapi/chat.c | 8 ++++++++ coreapi/linphonecore.h | 2 ++ coreapi/linphonecore_jni.cc | 14 ++++++++++++++ coreapi/private.h | 3 +++ include/sal/sal.h | 2 +- .../org/linphone/core/LinphoneChatMessage.java | 10 ++++++++++ .../linphone/core/LinphoneChatMessageImpl.java | 10 ++++++++++ 9 files changed, 64 insertions(+), 16 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 25402aef2..4eec76c6e 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void process_error( SalOp* op) { if (op->dir == SalOpDirOutgoing) { - op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + op->base.root->callbacks.text_delivery_update(op,403, "process error"); } else { ms_warning("unexpected io error for incoming message on op [%p]",op); } @@ -54,19 +54,8 @@ static void process_response_event(void *op_base, const belle_sip_response_event SalOp* op = (SalOp*)op_base; /*belle_sip_client_transaction_t *client_transaction=belle_sip_response_event_get_client_transaction(event);*/ int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); - SalTextDeliveryStatus status; - if (code>=100 && code <200) - status=SalTextDeliveryInProgress; - else if (code>=200 && code <300) - status=SalTextDeliveryDone; - else - status=SalTextDeliveryFailed; - if (status != SalTextDeliveryInProgress) { - /*reset op to make sure transaction terminated does not need op - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*/ - } - op->base.root->callbacks.text_delivery_update(op,status); - + const char *reason = belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event)); + op->base.root->callbacks.text_delivery_update(op,code, reason); } 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 diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f22d35f20..fe9b53aef 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1024,7 +1024,17 @@ 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){ +static SalTextDeliveryStatus code_to_text_delivery_status(int code) { + if (code>=100 && code <200) + return SalTextDeliveryInProgress; + else if (code>=200 && code <300) + return SalTextDeliveryDone; + else + return SalTextDeliveryFailed; +} + +static void text_delivery_update(SalOp *op, int code, const char *reason){ + SalTextDeliveryStatus status = code_to_text_delivery_status(code); LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); const MSList* calls; @@ -1035,6 +1045,8 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ calls = linphone_core_get_calls(chat_msg->chat_room->lc); chat_msg->state=chatStatusSal2Linphone(status); + chat_msg->response_code=code; + chat_msg->response_reason=ms_strdup(reason); linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { ms_message("Notifying text delivery with status %i",chat_msg->state); diff --git a/coreapi/chat.c b/coreapi/chat.c index 6dc8ae57a..2a756fef9 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -786,9 +786,17 @@ void linphone_chat_message_destroy(LinphoneChatMessage* msg) { 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); + if (msg->response_reason) ms_free(msg->response_reason); ms_free(msg); } +int linphone_chat_message_get_response_code(LinphoneChatMessage* msg) { + return msg->response_code; +} + +const char *linphone_chat_message_get_response_reason(LinphoneChatMessage* msg) { + return msg->response_reason; +} /** * @} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index e91d627ac..28d459d15 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1044,6 +1044,8 @@ LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneCha LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message); LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message); LINPHONE_PUBLIC unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message); +LINPHONE_PUBLIC int linphone_chat_message_get_response_code(LinphoneChatMessage* msg); +LINPHONE_PUBLIC const char *linphone_chat_message_get_response_reason(LinphoneChatMessage* msg); /** * @} */ diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 3ac117faa..7051c6abe 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2324,6 +2324,20 @@ extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNIEnv return jvalue; } +extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getResponseCode(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return linphone_chat_message_get_response_code((LinphoneChatMessage*)ptr); +} + +extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getResponseReason(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + const char *reason = linphone_chat_message_get_response_reason((LinphoneChatMessage*)ptr); + return env->NewStringUTF(reason); + +} + extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getCustomHeader(JNIEnv* env ,jobject thiz ,jlong ptr, jstring jheader_name) { diff --git a/coreapi/private.h b/coreapi/private.h index a2264af68..af5459035 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -25,6 +25,7 @@ #ifndef _PRIVATE_H #define _PRIVATE_H #ifdef __cplusplus + extern "C" { #endif #include "linphonecore.h" @@ -145,6 +146,8 @@ struct _LinphoneChatMessage { LinphoneChatMessageState state; bool_t is_read; unsigned int storage_id; + int response_code; + char *response_reason; }; typedef struct StunCandidate{ diff --git a/include/sal/sal.h b/include/sal/sal.h index 5c93786a9..a216730b1 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -391,7 +391,7 @@ typedef void (*SalOnVfuRequest)(SalOp *op); 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 (*SalOnTextDeliveryUpdate)(SalOp *op, int code, const char *reason); typedef void (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason); diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index 8345df382..c6985a33e 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -141,4 +141,14 @@ public interface LinphoneChatMessage { * @return the id used to id this message in the database */ int getStorageId(); + + /** + * @return the response code or 0 if no response received + */ + int getResponseCode(); + + /** + * @return the response reason or null if no response received + */ + String getResponseReason(); } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 8ce49c747..a6f591bfa 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -14,6 +14,8 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native boolean isOutgoing(long ptr); private native void store(long ptr); private native int getStorageId(long ptr); + private native int getResponseCode(long ptr); + private native String getResponseReason(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -94,4 +96,12 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public int getStorageId() { return getStorageId(nativePtr); } + + public int getResponseCode() { + return getResponseCode(nativePtr); + } + + public String getResponseReason() { + return getResponseReason(nativePtr); + } } From eab65df8f3a743dbc8149ab54a0af5dc4d415294 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Wed, 12 Feb 2014 14:53:29 +0100 Subject: [PATCH 219/439] Only consider registering configs in linphone_core_lookup_known_proxy --- coreapi/linphonecore.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 5a9b834e6..b95ee4e74 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2494,11 +2494,12 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L } } - /*otherwise iterate through the other proxy config and return the first matching*/ + /*otherwise iterate through the other proxy config and return the first enabled matching*/ for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; const char *domain=linphone_proxy_config_get_domain(cfg); - if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ + bool_t enabled = linphone_proxy_config_register_enabled(cfg); + if (enabled && domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ found_cfg=cfg; goto end; } @@ -2506,7 +2507,8 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L end: if (found_cfg!=NULL && found_cfg!=default_cfg){ ms_debug("Overriding default proxy setting for this call/message/subscribe operation."); - }else found_cfg=default_cfg; + } + else found_cfg=default_cfg; return found_cfg; } From 8367c0fef2688095699cc1d570be91c69b333a83 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Wed, 12 Feb 2014 14:11:12 +0100 Subject: [PATCH 220/439] More builder-like interface for LinphoneProxyConfig --- java/common/org/linphone/core/LinphoneProxyConfig.java | 5 ++--- java/impl/org/linphone/core/LinphoneProxyConfigImpl.java | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index 90d91e73a..e613fd194 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -30,7 +30,7 @@ public interface LinphoneProxyConfig { *Because proxy configuration must be consistent, applications MUST call {@link #edit()} before doing any attempts to modify proxy configuration (such as identity, proxy address and so on). *Once the modifications are done, then the application must call {@link #done()} to commit the changes. */ - public void edit(); + public LinphoneProxyConfig edit(); /** * Commits modification made to the proxy configuration. */ @@ -65,9 +65,8 @@ public interface LinphoneProxyConfig { * Enable register for this proxy config. * Register message is issued after call to {@link #done()} * @param value - * @throws LinphoneCoreException */ - public void enableRegister(boolean value) throws LinphoneCoreException; + public LinphoneProxyConfig enableRegister(boolean value); /** * @return true if registration to the proxy is enabled. */ diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 9f24dcbe8..2fe08ad91 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -84,16 +84,18 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { private native int lookupCCCFromIso(long nativePtr, String iso); private native int lookupCCCFromE164(long nativePtr, String e164); - public void enableRegister(boolean value) { + public LinphoneProxyConfig enableRegister(boolean value) { enableRegister(nativePtr,value); + return this; } public void done() { done(nativePtr); } - public void edit() { + public LinphoneProxyConfig edit() { edit(nativePtr); + return this; } public void setIdentity(String identity) throws LinphoneCoreException { From dba5a2337a86db8a29fc358fc677d0c29590e526 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Feb 2014 16:58:12 +0100 Subject: [PATCH 221/439] gtk app remote provisioning in progress --- coreapi/linphonecore.h | 22 +++++++++++++++++++++- coreapi/remote_provisioning.c | 15 ++++++++++++--- gtk/config-fetching.c | 32 +++++++++++++++++++++++++++++++- gtk/linphone.h | 6 +++++- gtk/main.c | 14 ++++++++++++-- 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 28d459d15..fd042589e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2280,9 +2280,29 @@ typedef struct _LinphoneContactProvider LinphoneContactProvider; typedef void (*ContactSearchCallback)( LinphoneContactSearch* id, MSList* friends, void* data ); -/** Remote provisioning +/* + * Remote provisioning */ +/** + * Set URI where to download xml configuration file at startup. + * This can also be set from configuration file or factory config file, from [misc] section, item "config-uri". + * Calling this function does not load the configuration. It will write the value into configuration so that configuration + * from remote URI will take place at next LinphoneCore start. + * @param lc the linphone core + * @param uri the http or https uri to use in order to download the configuration. + * @ingroup initializing +**/ +LINPHONE_PUBLIC void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char*uri); + +/** + * Get provisioning URI. + * @param lc the linphone core + * @return the provisioning URI. + * @ingroup initializing +**/ +LINPHONE_PUBLIC const char* linphone_core_get_provisioning_uri(const LinphoneCore *lc); + typedef void (*ConfiguringCallback)(LinphoneCore *lc, LinphoneConfiguringState state, const char *message); /** diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c index fe4269a66..127dce956 100644 --- a/coreapi/remote_provisioning.c +++ b/coreapi/remote_provisioning.c @@ -16,8 +16,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "linphonecore.h" -#include "bellesip_sal/sal_impl.h" +#include "private.h" #include "xml2lpc.h" #define XML2LPC_CALLBACK_BUFFER_SIZE 1024 @@ -137,4 +136,14 @@ static void linphone_remote_provisioning_download(LinphoneCore *lc, const char * void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri, ConfiguringCallback cb) { linphone_callback = cb; linphone_remote_provisioning_download(lc, remote_provisioning_uri); -} \ No newline at end of file +} + +void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char*uri){ + if (linphone_core_ready(lc)){ + lp_config_set_string(lc->config,"misc","config-uri",uri); + } +} + +const char*linphone_core_get_provisioning_uri(const LinphoneCore *lc){ + return lp_config_get_string(lc->config,"misc","config-uri",NULL); +} diff --git a/gtk/config-fetching.c b/gtk/config-fetching.c index b9ce5cb70..cec611814 100644 --- a/gtk/config-fetching.c +++ b/gtk/config-fetching.c @@ -23,6 +23,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. void linphone_gtk_set_configuration_uri(GtkWidget *item){ GtkWidget *w=linphone_gtk_create_window("config-uri"); + GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); + const char *uri=linphone_core_get_provisioning_uri(linphone_gtk_get_core()); + gtk_entry_set_text(GTK_ENTRY(entry),uri); gtk_widget_show(w); } @@ -30,8 +33,9 @@ void linphone_gtk_config_uri_changed(GtkWidget *button){ GtkWidget *w=gtk_widget_get_toplevel(button); GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); const char *uri=gtk_entry_get_text(GTK_ENTRY(entry)); - if (uri){ + if (uri && strcmp(uri,"https://")!=0){/*not just the hint text*/ /*set provisionning uri to the core*/ + linphone_core_set_provisioning_uri(linphone_gtk_get_core(),uri); gtk_widget_destroy(w); } @@ -46,3 +50,29 @@ void linphone_gtk_config_uri_cancel(GtkWidget *button){ gtk_widget_destroy(w); } +GtkWidget * linphone_gtk_show_config_fetching(void){ + LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *w=linphone_gtk_create_window("provisioning-fetch"); + g_message("Fetching started"); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(w),_("fetching from %s"),linphone_core_get_provisioning_uri(lc)); +#if GTK_CHECK_VERSION(2,20,0) + { + GtkWidget *spinner=gtk_spinner_new(); + gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(w),spinner); + } +#endif + gtk_widget_show(w); + return w; +} + +void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state){ + LinphoneCore *lc=linphone_gtk_get_core(); + gtk_widget_destroy(w); + g_message("Fetching finished"); + if (state==LinphoneConfiguringFailed){ + GtkWidget *msg=gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,_("Downloading of remote configuration from %s failed."), + linphone_core_get_provisioning_uri(lc)); + gtk_widget_show(msg); + } +} + diff --git a/gtk/linphone.h b/gtk/linphone.h index 8f996244c..c1d4323ca 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -165,4 +165,8 @@ 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_schedule_restart(void); \ No newline at end of file +void linphone_gtk_schedule_restart(void); + +GtkWidget * linphone_gtk_show_config_fetching(void); +void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state); + diff --git a/gtk/main.c b/gtk/main.c index 8cc3a2790..691c52b9a 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -90,6 +90,7 @@ gchar *linphone_logfile=NULL; static gboolean workaround_gtk_entry_chinese_bug=FALSE; static gchar *custom_config_file=NULL; static gboolean restart=FALSE; +static GtkWidget *config_fetching_dialog=NULL; static GOptionEntry linphone_options[]={ { @@ -1248,7 +1249,8 @@ static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){ } static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { - + if (config_fetching_dialog) linphone_gtk_close_config_fetching(config_fetching_dialog, status); + config_fetching_dialog=NULL; } static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){ @@ -1362,8 +1364,16 @@ void linphone_gtk_notify(LinphoneCall *call, const char *msg){ static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str){ switch(state){ + case LinphoneGlobalStartup: + the_core=lc; + break; + case LinphoneGlobalConfiguring: + if (linphone_core_get_provisioning_uri(lc)){ + config_fetching_dialog=linphone_gtk_show_config_fetching(); + } + break; case LinphoneGlobalOn: - if (the_core) linphone_gtk_init_ui(); + linphone_gtk_init_ui(); break; default: break; From 33df2c8fec165c9723f463467fc9ace609dfbcc0 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 12 Feb 2014 17:03:03 +0100 Subject: [PATCH 222/439] add a test, for credential provided in auth cb (SIP Message case) --- tester/message_tester.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tester/message_tester.c b/tester/message_tester.c index cf99c1013..c9c52cfe8 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -94,6 +94,42 @@ static void text_message(void) { linphone_core_manager_destroy(pauline); } +static LinphoneAuthInfo* text_message_with_credential_from_auth_cb_auth_info; +static void text_message_with_credential_from_auth_cb_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { + stats* counters; + ms_message("text_message_with_credential_from_auth_cb:Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + counters = get_stats(lc); + counters->number_of_auth_info_requested++; + linphone_core_add_auth_info(lc,text_message_with_credential_from_auth_cb_auth_info); /*add stored authentication info to LinphoneCore*/ +} + + +static void text_message_with_credential_from_auth_cb(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + text_message_with_credential_from_auth_cb_auth_info=linphone_auth_info_clone((LinphoneAuthInfo*)(linphone_core_get_auth_info_list(marie->lc)->data)); + + /*to force cb to be called*/ + linphone_core_clear_all_auth_info(marie->lc); + marie->lc->vtable.auth_info_requested=text_message_with_credential_from_auth_cb_auth_info_requested; + + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + ms_free(to); + + + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void text_message_with_privacy(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -296,6 +332,7 @@ static void is_composing_notification(void) { test_t message_tests[] = { { "Text message", text_message }, + { "Text message with credentials from auth info cb", text_message_with_credential_from_auth_cb}, { "Text message with privacy", text_message_with_privacy }, { "Text message compatibility mode", text_message_compatibility_mode }, { "Text message with ack", text_message_with_ack }, From f76c0ead31ba645663f74690a5bf6ddb3612c72b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 12 Feb 2014 16:31:46 +0100 Subject: [PATCH 223/439] Improved remote provisioning code + added test suite for it --- coreapi/linphonecore.c | 18 +++++-- coreapi/linphonecore.h | 10 ---- coreapi/private.h | 9 ++++ coreapi/remote_provisioning.c | 71 ++++++------------------- coreapi/sal.c | 5 +- include/sal/sal.h | 2 + tester/Makefile.am | 4 +- tester/liblinphone_tester.c | 12 +++-- tester/liblinphone_tester.h | 6 +++ tester/marie_remote_404_rc | 2 + tester/marie_remote_invalid_rc | 2 + tester/marie_remote_rc | 2 + tester/marie_xml | 50 ++++++++++++++++++ tester/pauline_remote_rc | 2 + tester/pauline_xml | 45 ++++++++++++++++ tester/remote_provisioning_tester.c | 80 +++++++++++++++++++++++++++++ 16 files changed, 243 insertions(+), 77 deletions(-) create mode 100644 tester/marie_remote_404_rc create mode 100644 tester/marie_remote_invalid_rc create mode 100644 tester/marie_remote_rc create mode 100644 tester/marie_xml create mode 100644 tester/pauline_remote_rc create mode 100644 tester/pauline_xml create mode 100644 tester/remote_provisioning_tester.c diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b95ee4e74..1b62c3a11 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1265,7 +1265,7 @@ static void linphone_core_start(LinphoneCore * lc) { linphone_core_set_state(lc,LinphoneGlobalOn,"Ready"); } -static void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) { +void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) { if (lc->vtable.configuring_status) lc->vtable.configuring_status(lc, state, message); @@ -1274,6 +1274,7 @@ static void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfigurin static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata) { + const char *remote_provisioning_uri = NULL; ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); memset (lc, 0, sizeof (LinphoneCore)); lc->config=config; @@ -1358,15 +1359,21 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab lc->network_last_check = 0; lc->network_last_status = FALSE; + + lc->http_provider = belle_sip_stack_create_http_provider(sal_get_belle_sip_stack(lc->sal), "0.0.0.0"); + + certificates_config_read(lc); + belle_tls_verify_policy_t *tls_policy = belle_tls_verify_policy_new(); + belle_tls_verify_policy_set_root_ca(tls_policy, sal_get_root_ca(lc->sal)); + belle_http_provider_set_tls_verify_policy(lc->http_provider, tls_policy); if (lc->vtable.display_status) lc->vtable.display_status(lc, _("Configuring")); linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); - const char *remote_provisioning_uri = lp_config_get_string(lc->config, "app", "remote_provisioning", NULL); + remote_provisioning_uri = lp_config_get_string(lc->config, "app", "remote_provisioning", NULL); if (remote_provisioning_uri) { - certificates_config_read(lc); - linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri, linphone_configuring_terminated); + linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri); } else { linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); } @@ -5470,6 +5477,9 @@ void net_config_uninit(LinphoneCore *lc) { net_config_t *config=&lc->net_conf; + if (lc->http_provider) { + belle_sip_object_unref(lc->http_provider); + } if (config->stun_server!=NULL){ ms_free(config->stun_server); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index fd042589e..8fefaf7f6 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2303,16 +2303,6 @@ LINPHONE_PUBLIC void linphone_core_set_provisioning_uri(LinphoneCore *lc, const **/ LINPHONE_PUBLIC const char* linphone_core_get_provisioning_uri(const LinphoneCore *lc); -typedef void (*ConfiguringCallback)(LinphoneCore *lc, LinphoneConfiguringState state, const char *message); - -/** - * Download a remote provisioning file from the given uri and applies it to current lp config. - * A restart is requiered for the changes to be applied. - * @param lc the LinphoneCore - * @param remote_provisioning_uri the URI at which the remote provisioning file is available - */ -LINPHONE_PUBLIC void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri, ConfiguringCallback cb); - #ifdef __cplusplus } #endif diff --git a/coreapi/private.h b/coreapi/private.h index af5459035..ca9054d8f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -673,6 +673,7 @@ struct _LinphoneCore #ifdef BUILD_UPNP UpnpContext *upnp; #endif //BUILD_UPNP + belle_http_provider_t *http_provider; }; @@ -806,6 +807,14 @@ const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, cons void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); +/***************************************************************************** + * REMOTE PROVISIONING FUNCTIONS * + ****************************************************************************/ + +void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message); +void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri); + + /***************************************************************************** * XML UTILITY FUNCTIONS * ****************************************************************************/ diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c index 127dce956..99b4c1292 100644 --- a/coreapi/remote_provisioning.c +++ b/coreapi/remote_provisioning.c @@ -21,9 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define XML2LPC_CALLBACK_BUFFER_SIZE 1024 -static ConfiguringCallback linphone_callback = NULL; -static bool_t waiting_response = FALSE; - static void xml2lpc_callback(void *ctx, xml2lpc_log_level level, const char *fmt, va_list list) { char buffer[XML2LPC_CALLBACK_BUFFER_SIZE]; vsnprintf(buffer, XML2LPC_CALLBACK_BUFFER_SIZE, fmt, list); @@ -44,22 +41,18 @@ static void linphone_remote_provisioning_apply(LinphoneCore *lc, const char *xml if (result == 0) { lp_config_sync(linphone_core_get_config(lc)); xml2lpc_context_destroy(context); - if (linphone_callback) - linphone_callback(lc, LinphoneConfiguringSuccessful, NULL); + linphone_configuring_terminated(lc, LinphoneConfiguringSuccessful, NULL); } else { xml2lpc_context_destroy(context); - if (linphone_callback) - linphone_callback(lc, LinphoneConfiguringFailed, "convert failed"); + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "xml to lpc failed"); } } else { xml2lpc_context_destroy(context); - if (linphone_callback) - linphone_callback(lc, LinphoneConfiguringFailed, "set xml string failed"); + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "invalid xml"); } } static void belle_request_process_response_event(void *ctx, const belle_http_response_event_t *event) { - waiting_response = FALSE; LinphoneCore *lc = (LinphoneCore *)ctx; belle_sip_message_t *body = BELLE_SIP_MESSAGE(event->response); const char *message = belle_sip_message_get_body(body); @@ -67,75 +60,41 @@ static void belle_request_process_response_event(void *ctx, const belle_http_res if (belle_http_response_get_status_code(event->response) == 200) { linphone_remote_provisioning_apply(lc, message); } else { - if (linphone_callback) - linphone_callback(lc, LinphoneConfiguringFailed, message); + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http error"); } } static void belle_request_process_io_error(void *ctx, const belle_sip_io_error_event_t *event) { - waiting_response = FALSE; LinphoneCore *lc = (LinphoneCore *)ctx; - - if (linphone_callback) - linphone_callback(lc, LinphoneConfiguringFailed, "io error"); + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http io error"); } static void belle_request_process_timeout(void *ctx, const belle_sip_timeout_event_t *event) { - waiting_response = FALSE; LinphoneCore *lc = (LinphoneCore *)ctx; - - if (linphone_callback) - linphone_callback(lc, LinphoneConfiguringFailed, "timeout"); + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http timeout"); } static void belle_request_process_auth_requested(void *ctx, belle_sip_auth_event_t *event) { - waiting_response = FALSE; LinphoneCore *lc = (LinphoneCore *)ctx; - - if (linphone_callback) - linphone_callback(lc, LinphoneConfiguringFailed, "auth requested"); + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http auth requested"); } -static belle_http_request_listener_callbacks_t belle_request_listener = { - belle_request_process_response_event, - belle_request_process_io_error, - belle_request_process_timeout, - belle_request_process_auth_requested -}; +void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri) { + belle_http_request_listener_callbacks_t belle_request_listener = { + belle_request_process_response_event, + belle_request_process_io_error, + belle_request_process_timeout, + belle_request_process_auth_requested + }; -static void linphone_remote_provisioning_download(LinphoneCore *lc, const char *remote_provisioning_uri) { - belle_sip_object_pool_t *pool = belle_sip_object_pool_push(); - belle_sip_stack_t *stack = belle_sip_stack_new(NULL); - belle_http_request_listener_t *listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc); - belle_http_provider_t *provider = belle_sip_stack_create_http_provider(stack, "0.0.0.0"); - belle_http_request_t *request = belle_http_request_create( "GET", belle_generic_uri_parse(remote_provisioning_uri), NULL ); - belle_http_provider_send_request(provider, request, listener); - - waiting_response = TRUE; - while (waiting_response) { - belle_sip_stack_sleep(stack, 10); - } - - belle_sip_object_unref(pool); - belle_sip_object_unref(provider); - belle_sip_object_unref(stack); -} - -/** - * Fetches the remote provisioning from the given URI and tries to apply it to the current LpConfig - * @param lc the LinphoneCore - * @param remote_provisioning_uri the URI at which the provisioning is available - */ -void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri, ConfiguringCallback cb) { - linphone_callback = cb; - linphone_remote_provisioning_download(lc, remote_provisioning_uri); + belle_http_provider_send_request(lc->http_provider, request, listener); } void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char*uri){ diff --git a/coreapi/sal.c b/coreapi/sal.c index babb2af4d..de5f235df 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "config.h" #endif #include "sal/sal.h" +#include "bellesip_sal/sal_impl.h" #include @@ -626,5 +627,7 @@ int sal_body_has_type(const SalBody *body, const char *type, const char *subtype && strcmp(body->subtype,subtype)==0; } - +belle_sip_stack_t *sal_get_belle_sip_stack(Sal *sal) { + return sal->stack; +} diff --git a/include/sal/sal.h b/include/sal/sal.h index a216730b1..db2625329 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -697,4 +697,6 @@ int sal_body_has_type(const SalBody *body, const char *type, const char *subtype /*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/ int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size); +belle_sip_stack_t *sal_get_belle_sip_stack(Sal *sal); + #endif diff --git a/tester/Makefile.am b/tester/Makefile.am index f1d5f1f8e..22949b61f 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -1,4 +1,5 @@ EXTRA_DIST= empty_rc laure_rc marie_early_rc marie_no_sdp_rc marie_rc multi_account_lrc pauline_alt_rc \ + marie_remote_rc pauline_remote_rc marie_remote_404_rc marie_remote_invalid_rc \ pauline_rc pauline_wild_rc pauline_rc_tcp tester_hosts sounds images certificates @@ -15,7 +16,8 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ upnp_tester.c \ eventapi_tester.c \ flexisip_tester.c \ - stun_tester.c + stun_tester.c \ + remote_provisioning_tester.c #liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 9f654542c..7a7346f51 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -25,7 +25,7 @@ #include "CUnit/CUCurses.h" #endif -static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file); +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data); static test_suite_t **test_suite = NULL; static int nb_test_suites = 0; @@ -90,7 +90,7 @@ void reset_counters( stats* counters) { memset(counters,0,sizeof(stats)); } -static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file) { +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) { LinphoneCore* lc; char filepath[256]={0}; char ringpath[256]={0}; @@ -106,7 +106,7 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* CU_ASSERT_TRUE_FATAL(ortp_file_exist(filepath)==0); } - lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); + lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL, user_data); sal_enable_test_features(lc->sal,TRUE); snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cafile.pem", path); @@ -200,9 +200,10 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f 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); + mgr->v_table.configuring_status=linphone_configuration_status; + reset_counters(&mgr->stat); + mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_file, mgr); /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ if (check_for_proxies && rc_file) /**/ proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)); @@ -328,6 +329,7 @@ void liblinphone_tester_init(void) { add_test_suite(&stun_test_suite); add_test_suite(&event_test_suite); add_test_suite(&flexisip_test_suite); + add_test_suite(&remote_provisioning_test_suite); } void liblinphone_tester_uninit(void) { diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index b2987a408..edf51e1fb 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -55,6 +55,7 @@ extern test_suite_t upnp_test_suite; extern test_suite_t event_test_suite; extern test_suite_t flexisip_test_suite; extern test_suite_t stun_test_suite; +extern test_suite_t remote_provisioning_test_suite; extern int liblinphone_tester_nb_test_suites(void); @@ -173,6 +174,10 @@ typedef struct _stats { int number_of_LinphonePublishExpiring; int number_of_LinphonePublishError; int number_of_LinphonePublishCleared; + + int number_of_LinphoneConfiguringSkipped; + int number_of_LinphoneConfiguringFailed; + int number_of_LinphoneConfiguringSuccessful; }stats; typedef struct _LinphoneCoreManager { @@ -203,6 +208,7 @@ void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state); void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state); void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content); +void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); LinphoneAddress * create_linphone_address(const char * domain); bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value); diff --git a/tester/marie_remote_404_rc b/tester/marie_remote_404_rc new file mode 100644 index 000000000..1ca04f8de --- /dev/null +++ b/tester/marie_remote_404_rc @@ -0,0 +1,2 @@ +[app] +remote_provisioning=http://smtp.linphone.org/marie_404 diff --git a/tester/marie_remote_invalid_rc b/tester/marie_remote_invalid_rc new file mode 100644 index 000000000..1e52d7f37 --- /dev/null +++ b/tester/marie_remote_invalid_rc @@ -0,0 +1,2 @@ +[app] +remote_provisioning=http://smtp.linphone.org/marie_invalid diff --git a/tester/marie_remote_rc b/tester/marie_remote_rc new file mode 100644 index 000000000..faeb2cdd0 --- /dev/null +++ b/tester/marie_remote_rc @@ -0,0 +1,2 @@ +[app] +remote_provisioning=http://smtp.linphone.org/marie_xml diff --git a/tester/marie_xml b/tester/marie_xml new file mode 100644 index 000000000..5818930ba --- /dev/null +++ b/tester/marie_xml @@ -0,0 +1,50 @@ + + +
+ -1 + -1 + -1 + 0 + 0 + 0 + 1 +
+
+ marie + marie + secret + sip.example.org +
+
+ sip.example.org;transport=tcp + sip.example.org;transport=tcp;lr + sip:marie@sip.example.org + 3600 + 1 + 0 + 0 +
+
+ "Paupoche" <sip:pauline@sip.example.org> + accept + 0 +
+
+ 8070 + 9072 +
+
+ 0 + 0 + 0 + vga + 0 + 0 + 0 + 0 + StaticImage: Static picture +
+
+ 0 #to not overload cpu in case of VG +
+
diff --git a/tester/pauline_remote_rc b/tester/pauline_remote_rc new file mode 100644 index 000000000..276bb1f54 --- /dev/null +++ b/tester/pauline_remote_rc @@ -0,0 +1,2 @@ +[app] +remote_provisioning=https://smtp.linphone.org/pauline_xml diff --git a/tester/pauline_xml b/tester/pauline_xml new file mode 100644 index 000000000..cc952af82 --- /dev/null +++ b/tester/pauline_xml @@ -0,0 +1,45 @@ + + +
+ -1 + -1 + -1 + 0 + 0 + 0 + 1 +
+
+ pauline + pauline + secret + sip.example.org +
+
+ sip2.linphone.org;transport=tls + sip2.linphone.org;transport=tls + sip:pauline@sip.example.org + 3600 + 1 + 0 + 0 +
+
+ 8090 + 9092 +
+
+ 0 + 0 + 0 + vga + 0 + 0 + 0 + 0 + StaticImage: Static picture +
+
+ 0 #to not overload cpu in case of VG +
+
diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c new file mode 100644 index 000000000..7d73418bf --- /dev/null +++ b/tester/remote_provisioning_tester.c @@ -0,0 +1,80 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + +void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + stats* counters = get_stats(lc); + if (status == LinphoneConfiguringSkipped) { + counters->number_of_LinphoneConfiguringSkipped++; + } else if (status == LinphoneConfiguringFailed) { + counters->number_of_LinphoneConfiguringFailed++; + } else if (status == LinphoneConfiguringSuccessful) { + counters->number_of_LinphoneConfiguringSuccessful++; + } +} + +static void remote_provisioning_skipped(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_rc", FALSE); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSkipped,1)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_http(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_remote_rc"); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_https(void) { + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_remote_rc"); + CU_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneConfiguringSuccessful,1)); + linphone_core_manager_destroy(pauline); +} + +static void remote_provisioning_not_found(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_remote_404_rc"); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringFailed,1)); + linphone_core_manager_destroy(marie); +} + +static void remote_provisioning_invalid(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_remote_invalid_rc"); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringFailed,1)); + linphone_core_manager_destroy(marie); +} + +test_t remote_provisioning_tests[] = { + { "Remote provisioning skipped", remote_provisioning_skipped }, + { "Remote provisioning successful behind http", remote_provisioning_http }, + { "Remote provisioning successful behind https", remote_provisioning_https }, + { "Remote provisioning 404 not found", remote_provisioning_not_found }, + { "Remote provisioning invalid", remote_provisioning_invalid } +}; + +test_suite_t remote_provisioning_test_suite = { + "RemoteProvisioning", + NULL, + NULL, + sizeof(remote_provisioning_tests) / sizeof(remote_provisioning_tests[0]), + remote_provisioning_tests +}; \ No newline at end of file From 92f0b5d3d3da2c386ee71e3ae2d3f096c5d0c1b5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Feb 2014 17:45:16 +0100 Subject: [PATCH 224/439] provisioning ok --- coreapi/linphonecore.c | 2 +- gtk/provisioning-fetch.ui | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 gtk/provisioning-fetch.ui diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1b62c3a11..45bb40393 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1371,7 +1371,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab lc->vtable.display_status(lc, _("Configuring")); linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); - remote_provisioning_uri = lp_config_get_string(lc->config, "app", "remote_provisioning", NULL); + remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); if (remote_provisioning_uri) { linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri); } else { diff --git a/gtk/provisioning-fetch.ui b/gtk/provisioning-fetch.ui new file mode 100644 index 000000000..e2d6a0203 --- /dev/null +++ b/gtk/provisioning-fetch.ui @@ -0,0 +1,53 @@ + + + + + + False + 5 + Configuring... + dialog + True + Please wait while fetching configuration from server... + + + True + False + 2 + + + True + False + end + + + + + + + + + False + True + end + 0 + + + + + True + False + + + + + + True + True + 2 + + + + + + From 36b603f2e881d2ac7e0156b183e4eda56e165430 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Feb 2014 17:46:02 +0100 Subject: [PATCH 225/439] Revert "Only consider registering configs in linphone_core_lookup_known_proxy" This reverts commit eab65df8f3a743dbc8149ab54a0af5dc4d415294. --- coreapi/linphonecore.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 45bb40393..ea94da3fa 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2501,12 +2501,11 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L } } - /*otherwise iterate through the other proxy config and return the first enabled matching*/ + /*otherwise iterate through the other proxy config and return the first matching*/ for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; const char *domain=linphone_proxy_config_get_domain(cfg); - bool_t enabled = linphone_proxy_config_register_enabled(cfg); - if (enabled && domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ + if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ found_cfg=cfg; goto end; } @@ -2514,8 +2513,7 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L end: if (found_cfg!=NULL && found_cfg!=default_cfg){ ms_debug("Overriding default proxy setting for this call/message/subscribe operation."); - } - else found_cfg=default_cfg; + }else found_cfg=default_cfg; return found_cfg; } From 931c8ade5f624ba875e44932aa7ae53965ec34f0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Feb 2014 17:47:16 +0100 Subject: [PATCH 226/439] Revert "Expose chat message response code and reason." This reverts commit f021e9aa519ed263d180e1a3aed951e68dd0a62f. --- coreapi/bellesip_sal/sal_op_message.c | 17 ++++++++++++++--- coreapi/callbacks.c | 14 +------------- coreapi/chat.c | 8 -------- coreapi/linphonecore.h | 2 -- coreapi/linphonecore_jni.cc | 14 -------------- coreapi/private.h | 3 --- include/sal/sal.h | 2 +- .../org/linphone/core/LinphoneChatMessage.java | 10 ---------- .../linphone/core/LinphoneChatMessageImpl.java | 10 ---------- 9 files changed, 16 insertions(+), 64 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 4eec76c6e..25402aef2 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void process_error( SalOp* op) { if (op->dir == SalOpDirOutgoing) { - op->base.root->callbacks.text_delivery_update(op,403, "process error"); + op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); } else { ms_warning("unexpected io error for incoming message on op [%p]",op); } @@ -54,8 +54,19 @@ static void process_response_event(void *op_base, const belle_sip_response_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)); - const char *reason = belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event)); - op->base.root->callbacks.text_delivery_update(op,code, reason); + SalTextDeliveryStatus status; + if (code>=100 && code <200) + status=SalTextDeliveryInProgress; + else if (code>=200 && code <300) + status=SalTextDeliveryDone; + else + status=SalTextDeliveryFailed; + if (status != SalTextDeliveryInProgress) { + /*reset op to make sure transaction terminated does not need op + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*/ + } + op->base.root->callbacks.text_delivery_update(op,status); + } static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index fe9b53aef..f22d35f20 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1024,17 +1024,7 @@ static int op_equals(LinphoneCall *a, SalOp *b) { return a->op !=b; /*return 0 if equals*/ } -static SalTextDeliveryStatus code_to_text_delivery_status(int code) { - if (code>=100 && code <200) - return SalTextDeliveryInProgress; - else if (code>=200 && code <300) - return SalTextDeliveryDone; - else - return SalTextDeliveryFailed; -} - -static void text_delivery_update(SalOp *op, int code, const char *reason){ - SalTextDeliveryStatus status = code_to_text_delivery_status(code); +static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); const MSList* calls; @@ -1045,8 +1035,6 @@ static void text_delivery_update(SalOp *op, int code, const char *reason){ calls = linphone_core_get_calls(chat_msg->chat_room->lc); chat_msg->state=chatStatusSal2Linphone(status); - chat_msg->response_code=code; - chat_msg->response_reason=ms_strdup(reason); linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { ms_message("Notifying text delivery with status %i",chat_msg->state); diff --git a/coreapi/chat.c b/coreapi/chat.c index 2a756fef9..6dc8ae57a 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -786,17 +786,9 @@ void linphone_chat_message_destroy(LinphoneChatMessage* msg) { 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); - if (msg->response_reason) ms_free(msg->response_reason); ms_free(msg); } -int linphone_chat_message_get_response_code(LinphoneChatMessage* msg) { - return msg->response_code; -} - -const char *linphone_chat_message_get_response_reason(LinphoneChatMessage* msg) { - return msg->response_reason; -} /** * @} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 8fefaf7f6..0c6580bae 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1044,8 +1044,6 @@ LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneCha LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message); LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message); LINPHONE_PUBLIC unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message); -LINPHONE_PUBLIC int linphone_chat_message_get_response_code(LinphoneChatMessage* msg); -LINPHONE_PUBLIC const char *linphone_chat_message_get_response_reason(LinphoneChatMessage* msg); /** * @} */ diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 7051c6abe..3ac117faa 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2324,20 +2324,6 @@ extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNIEnv return jvalue; } -extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getResponseCode(JNIEnv* env - ,jobject thiz - ,jlong ptr) { - return linphone_chat_message_get_response_code((LinphoneChatMessage*)ptr); -} - -extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getResponseReason(JNIEnv* env - ,jobject thiz - ,jlong ptr) { - const char *reason = linphone_chat_message_get_response_reason((LinphoneChatMessage*)ptr); - return env->NewStringUTF(reason); - -} - extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getCustomHeader(JNIEnv* env ,jobject thiz ,jlong ptr, jstring jheader_name) { diff --git a/coreapi/private.h b/coreapi/private.h index ca9054d8f..a4ec17857 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -25,7 +25,6 @@ #ifndef _PRIVATE_H #define _PRIVATE_H #ifdef __cplusplus - extern "C" { #endif #include "linphonecore.h" @@ -146,8 +145,6 @@ struct _LinphoneChatMessage { LinphoneChatMessageState state; bool_t is_read; unsigned int storage_id; - int response_code; - char *response_reason; }; typedef struct StunCandidate{ diff --git a/include/sal/sal.h b/include/sal/sal.h index db2625329..7a7134754 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -391,7 +391,7 @@ typedef void (*SalOnVfuRequest)(SalOp *op); 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, int code, const char *reason); +typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status); typedef void (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason); diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index c6985a33e..8345df382 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -141,14 +141,4 @@ public interface LinphoneChatMessage { * @return the id used to id this message in the database */ int getStorageId(); - - /** - * @return the response code or 0 if no response received - */ - int getResponseCode(); - - /** - * @return the response reason or null if no response received - */ - String getResponseReason(); } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index a6f591bfa..8ce49c747 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -14,8 +14,6 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native boolean isOutgoing(long ptr); private native void store(long ptr); private native int getStorageId(long ptr); - private native int getResponseCode(long ptr); - private native String getResponseReason(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -96,12 +94,4 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public int getStorageId() { return getStorageId(nativePtr); } - - public int getResponseCode() { - return getResponseCode(nativePtr); - } - - public String getResponseReason() { - return getResponseReason(nativePtr); - } } From 233061e8396ed74261cfc40cd3eca8ff63197f40 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 12 Feb 2014 19:42:41 +0100 Subject: [PATCH 227/439] remote provisioning sounds working good in GTK app --- gtk/config-fetching.c | 1 + tester/remote_provisioning_tester.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk/config-fetching.c b/gtk/config-fetching.c index cec611814..7d6be5d07 100644 --- a/gtk/config-fetching.c +++ b/gtk/config-fetching.c @@ -72,6 +72,7 @@ void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState s if (state==LinphoneConfiguringFailed){ GtkWidget *msg=gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,_("Downloading of remote configuration from %s failed."), linphone_core_get_provisioning_uri(lc)); + g_signal_connect(G_OBJECT(msg),"response",(GCallback)gtk_widget_destroy,NULL); gtk_widget_show(msg); } } diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 7d73418bf..770e2a97d 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -77,4 +77,4 @@ test_suite_t remote_provisioning_test_suite = { NULL, sizeof(remote_provisioning_tests) / sizeof(remote_provisioning_tests[0]), remote_provisioning_tests -}; \ No newline at end of file +}; From e8bc43d75e08846f9c59441842680b28b23d8e93 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 13 Feb 2014 11:16:45 +0100 Subject: [PATCH 228/439] Fixed and improved tests for remote provisioning --- tester/marie_remote_404_rc | 4 ++-- tester/marie_remote_invalid_rc | 4 ++-- tester/marie_remote_rc | 4 ++-- tester/pauline_remote_rc | 4 ++-- tester/remote_provisioning_tester.c | 3 +++ 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/tester/marie_remote_404_rc b/tester/marie_remote_404_rc index 1ca04f8de..a47d68ce7 100644 --- a/tester/marie_remote_404_rc +++ b/tester/marie_remote_404_rc @@ -1,2 +1,2 @@ -[app] -remote_provisioning=http://smtp.linphone.org/marie_404 +[misc] +config-uri=http://smtp.linphone.org/marie_404 diff --git a/tester/marie_remote_invalid_rc b/tester/marie_remote_invalid_rc index 1e52d7f37..3d4dca248 100644 --- a/tester/marie_remote_invalid_rc +++ b/tester/marie_remote_invalid_rc @@ -1,2 +1,2 @@ -[app] -remote_provisioning=http://smtp.linphone.org/marie_invalid +[misc] +config-uri=http://smtp.linphone.org/marie_invalid diff --git a/tester/marie_remote_rc b/tester/marie_remote_rc index faeb2cdd0..c581e0995 100644 --- a/tester/marie_remote_rc +++ b/tester/marie_remote_rc @@ -1,2 +1,2 @@ -[app] -remote_provisioning=http://smtp.linphone.org/marie_xml +[misc] +config-uri=http://smtp.linphone.org/marie_xml diff --git a/tester/pauline_remote_rc b/tester/pauline_remote_rc index 276bb1f54..3594a2f94 100644 --- a/tester/pauline_remote_rc +++ b/tester/pauline_remote_rc @@ -1,2 +1,2 @@ -[app] -remote_provisioning=https://smtp.linphone.org/pauline_xml +[misc] +config-uri=https://smtp.linphone.org/pauline_xml diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 770e2a97d..45c238d63 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -23,6 +23,8 @@ #include "liblinphone_tester.h" void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + ms_message("Configuring state = %i with message %s", status, message); + stats* counters = get_stats(lc); if (status == LinphoneConfiguringSkipped) { counters->number_of_LinphoneConfiguringSkipped++; @@ -42,6 +44,7 @@ static void remote_provisioning_skipped(void) { static void remote_provisioning_http(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_remote_rc"); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneRegistrationOk,1)); linphone_core_manager_destroy(marie); } From 93f5e85967cb1e62a4000c75b1e32bacddae4a13 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Thu, 13 Feb 2014 11:54:11 +0100 Subject: [PATCH 229/439] Expose chat message reason based on LinphoneReason. The response code is not exposed to allow mrtp in the future. There is no possibility to retrieve the code or the sip reason phrase. --- coreapi/bellesip_sal/sal_op_message.c | 5 +++-- coreapi/callbacks.c | 3 ++- coreapi/chat.c | 4 ++++ coreapi/linphonecore.h | 1 + coreapi/linphonecore_jni.cc | 6 ++++++ coreapi/private.h | 2 ++ include/sal/sal.h | 2 +- java/common/org/linphone/core/LinphoneChatMessage.java | 5 +++++ java/impl/org/linphone/core/LinphoneChatMessageImpl.java | 6 ++++++ 9 files changed, 30 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 25402aef2..10507a12f 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void process_error( SalOp* op) { if (op->dir == SalOpDirOutgoing) { - op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed, SalReasonUnknown); } else { ms_warning("unexpected io error for incoming message on op [%p]",op); } @@ -65,8 +65,9 @@ static void process_response_event(void *op_base, const belle_sip_response_event /*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); + SalReason reason = code == 403 ? SalReasonForbidden : SalReasonUnknown; + op->base.root->callbacks.text_delivery_update(op,status, reason); } 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 diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f22d35f20..13ac204f7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1024,7 +1024,7 @@ 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){ +static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status, SalReason reason){ LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); const MSList* calls; @@ -1035,6 +1035,7 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ calls = linphone_core_get_calls(chat_msg->chat_room->lc); chat_msg->state=chatStatusSal2Linphone(status); + chat_msg->reason=reason; linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { ms_message("Notifying text delivery with status %i",chat_msg->state); diff --git a/coreapi/chat.c b/coreapi/chat.c index 6dc8ae57a..39003fbbf 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -790,6 +790,10 @@ void linphone_chat_message_destroy(LinphoneChatMessage* msg) { } +LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) { + return linphone_reason_from_sal(msg->reason); +} + /** * @} */ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 0c6580bae..aec4df508 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1044,6 +1044,7 @@ LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneCha LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message); LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message); LINPHONE_PUBLIC unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message); +LINPHONE_PUBLIC LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg); /** * @} */ diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 3ac117faa..760ce3f29 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2324,6 +2324,12 @@ extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNIEnv return jvalue; } +extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getReason(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return linphone_chat_message_get_reason((LinphoneChatMessage*)ptr); +} + extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getCustomHeader(JNIEnv* env ,jobject thiz ,jlong ptr, jstring jheader_name) { diff --git a/coreapi/private.h b/coreapi/private.h index a4ec17857..89d4ae7b1 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -25,6 +25,7 @@ #ifndef _PRIVATE_H #define _PRIVATE_H #ifdef __cplusplus + extern "C" { #endif #include "linphonecore.h" @@ -145,6 +146,7 @@ struct _LinphoneChatMessage { LinphoneChatMessageState state; bool_t is_read; unsigned int storage_id; + LinphoneReason reason; }; typedef struct StunCandidate{ diff --git a/include/sal/sal.h b/include/sal/sal.h index 7a7134754..644649d13 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -391,7 +391,7 @@ typedef void (*SalOnVfuRequest)(SalOp *op); 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 (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus, SalReason); typedef void (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason); diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index 8345df382..7d5d8b472 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -141,4 +141,9 @@ public interface LinphoneChatMessage { * @return the id used to id this message in the database */ int getStorageId(); + + /** + * @return the reason if response received + */ + Reason getReason(); } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 8ce49c747..2708a82af 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -94,4 +94,10 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public int getStorageId() { return getStorageId(nativePtr); } + + private native int getReason(long ptr); + + public Reason getReason() { + return Reason.fromInt(getReason(nativePtr)); + } } From 0f312991392a3111d52831613014c574e5901fe2 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Thu, 13 Feb 2014 16:08:09 +0100 Subject: [PATCH 230/439] Prefer default, then registering proxy in linphone_core_lookup_known_proxy Simple backward compatible evolution of the algorithm. Not registering proxy does not mean disabled: they are the fallback in case no other proxy matches. A better description of the proxy config modes would be: - enabled; - noregister; - disabled. However, it is a bit invasive as many places enable/disable registrations. --- coreapi/linphonecore.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ea94da3fa..b589c17b0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2490,9 +2490,10 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){ const MSList *elem; LinphoneProxyConfig *found_cfg=NULL; + LinphoneProxyConfig *found_noreg_cfg=NULL; LinphoneProxyConfig *default_cfg=lc->default_proxy; - /*always prefer the default proxy if it is matching the destination uri*/ + /*return default proxy if it is matching the destination uri*/ if (default_cfg){ const char *domain=linphone_proxy_config_get_domain(default_cfg); if (strcmp(domain,linphone_address_get_domain(uri))==0){ @@ -2501,16 +2502,21 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L } } - /*otherwise iterate through the other proxy config and return the first matching*/ + /*otherwise return first registering matching, otherwise first matching */ for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; const char *domain=linphone_proxy_config_get_domain(cfg); if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ - found_cfg=cfg; - goto end; + if (linphone_proxy_config_register_enabled(cfg)) { + found_cfg=cfg; + goto end; + } else if (!found_noreg_cfg){ + found_noreg_cfg=cfg; + } } } end: + if (found_noreg_cfg) found_cfg = found_noreg_cfg; if (found_cfg!=NULL && found_cfg!=default_cfg){ ms_debug("Overriding default proxy setting for this call/message/subscribe operation."); }else found_cfg=default_cfg; From 03b14b5123c71b592f02292d332c4d14ebe9c892 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 13 Feb 2014 21:43:33 +0100 Subject: [PATCH 231/439] fix bug in gtk UI when changing provisioning uri two times. clean network-type in login window, which is not so useful. --- gtk/loginframe.c | 26 +------------------------- gtk/main.c | 7 +++++-- gtk/main.ui | 2 -- gtk/singleinstance.c | 2 ++ 4 files changed, 8 insertions(+), 29 deletions(-) diff --git a/gtk/loginframe.c b/gtk/loginframe.c index ef4ae9e05..bd8a8643f 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -23,10 +23,6 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button); void test_button_clicked_cb(GtkWidget *button); void linphone_gtk_exit_login_frame(void); -enum { - NetworkKindAdsl, - NetworkKindOpticalFiber -}; static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd){ if (sip_setup_context_login_account(ssctx,identity,passwd)==0){ @@ -61,24 +57,16 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ gchar *str; LinphoneAddress *from; LinphoneCore *lc=linphone_gtk_get_core(); - int nettype; const char *passwd=NULL; - if (linphone_core_get_download_bandwidth(lc)==512 && - linphone_core_get_upload_bandwidth(lc)==512) - nettype=NetworkKindOpticalFiber; - else nettype=NetworkKindAdsl; - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"login_internet_kind")),nettype); - //gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"internet_kind")),nettype); - if (linphone_gtk_get_ui_config_int("automatic_login",0) ){ g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg); return; } { - const char *login_image=linphone_gtk_get_ui_config("login_image",NULL); + const char *login_image=linphone_gtk_get_ui_config("login_image","linphone-banner.png"); if (login_image){ GdkPixbuf *pbuf=create_pixbuf (login_image); gtk_image_set_from_pixbuf (GTK_IMAGE(linphone_gtk_get_widget(mw,"login_image")), @@ -166,15 +154,3 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ /*we need to refresh the identities since the proxy config may have changed.*/ linphone_gtk_load_identities(); } - -void linphone_gtk_internet_kind_changed(GtkWidget *combo){ - int netkind_id=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); - LinphoneCore *lc=linphone_gtk_get_core(); - if (netkind_id==NetworkKindAdsl){ - linphone_core_set_upload_bandwidth(lc,256); - linphone_core_set_download_bandwidth(lc,512); - }else if (netkind_id==NetworkKindOpticalFiber){ - linphone_core_set_upload_bandwidth(lc,512); - linphone_core_set_download_bandwidth(lc,512); - } -} diff --git a/gtk/main.c b/gtk/main.c index 691c52b9a..bf882fa4b 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -80,6 +80,7 @@ static gint main_window_x=0; static gint main_window_y=0; #endif static gboolean verbose=0; +static gboolean quit_done=FALSE; static gboolean auto_answer = 0; static gchar * addr_to_call = NULL; static gboolean no_video=FALSE; @@ -2085,11 +2086,12 @@ static void linphone_gtk_quit_core(void){ } static void linphone_gtk_quit(void){ - static gboolean quit_done=FALSE; if (!quit_done){ quit_done=TRUE; linphone_gtk_quit_core(); linphone_gtk_uninit_instance(); + g_object_unref(icon); + icon=NULL; #ifdef HAVE_NOTIFY notify_uninit(); #endif @@ -2291,12 +2293,13 @@ core_start: linphone_gtk_quit(); if (restart){ + quit_done=FALSE; restart=FALSE; goto core_start; } #ifndef HAVE_GTK_OSX /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/ - gtk_status_icon_set_visible(icon,FALSE); + if (icon) gtk_status_icon_set_visible(icon,FALSE); #endif free(progpath); return 0; diff --git a/gtk/main.ui b/gtk/main.ui index 96d3e11c0..190af22a1 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1656,7 +1656,6 @@ - True False Internet connection: @@ -1700,7 +1699,6 @@ - True False model4 0 diff --git a/gtk/singleinstance.c b/gtk/singleinstance.c index c9550a09f..5bb70c002 100644 --- a/gtk/singleinstance.c +++ b/gtk/singleinstance.c @@ -65,7 +65,9 @@ static void linphone_gtk_init_pipe(const char *name){ server_pipe=ortp_server_pipe_create(name); if (server_pipe==(ortp_pipe_t)-1){ g_warning("Fail to create server pipe for name %s: %s",name,strerror(errno)); + return; } + server_pipe_running=TRUE; ms_thread_create(&pipe_thread,NULL,server_pipe_thread,NULL); } From c88c845e0c7ec22da192d28f154ad689d0711166 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 13 Feb 2014 21:49:34 +0100 Subject: [PATCH 232/439] better handling of sip chat message failures --- coreapi/bellesip_sal/sal_op_message.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 10507a12f..0db775a3c 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -55,6 +55,9 @@ static void process_response_event(void *op_base, const belle_sip_response_event /*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; + SalReason reason=SalReasonUnknown; + SalError err=SalErrorNone; + if (code>=100 && code <200) status=SalTextDeliveryInProgress; else if (code>=200 && code <300) @@ -65,8 +68,7 @@ static void process_response_event(void *op_base, const belle_sip_response_event /*reset op to make sure transaction terminated does not need op belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*/ } - - SalReason reason = code == 403 ? SalReasonForbidden : SalReasonUnknown; + sal_compute_sal_errors_from_code(code,&err,&reason); op->base.root->callbacks.text_delivery_update(op,status, reason); } static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { From c639d6503640d2f6c6a7063bb9b05e993b3e9b02 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 13 Feb 2014 22:36:36 +0100 Subject: [PATCH 233/439] add user ID to login screen, fix bugs --- coreapi/proxy.c | 2 +- coreapi/siplogin.c | 5 +++-- coreapi/sipsetup.c | 4 ++-- coreapi/sipsetup.h | 4 ++-- coreapi/sipwizard.c | 2 +- gtk/loginframe.c | 17 ++++++++++++----- gtk/main.ui | 40 +++++++++++++++++++++++++++++++++------- 7 files changed, 54 insertions(+), 20 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 214aabea8..0c710cb3a 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1120,7 +1120,7 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){ } caps=sip_setup_context_get_capabilities(ssc); if (caps & SIP_SETUP_CAP_ACCOUNT_MANAGER){ - if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL)!=0){ + if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL,NULL)!=0){ if (lc->vtable.display_warning){ char *tmp=ms_strdup_printf(_("Could not login as %s"),cfg->reg_identity); lc->vtable.display_warning(lc,tmp); diff --git a/coreapi/siplogin.c b/coreapi/siplogin.c index c63d8af1e..b70f50f0e 100644 --- a/coreapi/siplogin.c +++ b/coreapi/siplogin.c @@ -49,7 +49,7 @@ static void guess_display_name(LinphoneAddress *from){ ms_free(dn); } -static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char *passwd){ +static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid){ LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); LinphoneCore *lc=linphone_proxy_config_get_core(cfg); LinphoneAuthInfo *auth; @@ -66,7 +66,8 @@ static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char tmp=linphone_address_as_string(parsed_uri); linphone_proxy_config_set_identity(cfg,tmp); if (passwd ) { - auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL,NULL); + auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),userid,passwd,NULL,NULL, + linphone_address_get_domain(parsed_uri)); linphone_core_add_auth_info(lc,auth); } linphone_proxy_config_enable_register(cfg,TRUE); diff --git a/coreapi/sipsetup.c b/coreapi/sipsetup.c index a5b846a64..91abf5d62 100644 --- a/coreapi/sipsetup.c +++ b/coreapi/sipsetup.c @@ -146,7 +146,7 @@ int sip_setup_context_account_validated(SipSetupContext *ctx, const char *uri){ return -1; } -int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd){ +int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid){ LinphoneAddress *from=linphone_address_new(uri); if (from==NULL) { ms_warning("Fail to parse %s",uri); @@ -156,7 +156,7 @@ int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, cons strncpy(ctx->username,linphone_address_get_username(from),sizeof(ctx->username)); linphone_address_destroy(from); if (ctx->funcs->login_account) - return ctx->funcs->login_account(ctx,uri,passwd); + return ctx->funcs->login_account(ctx,uri,passwd,userid); return -1; } diff --git a/coreapi/sipsetup.h b/coreapi/sipsetup.h index 2aefbee5c..dad51f13e 100644 --- a/coreapi/sipsetup.h +++ b/coreapi/sipsetup.h @@ -98,7 +98,7 @@ struct _SipSetup{ void (*uninit_instance)(SipSetupContext *ctx); int (*account_exists)(SipSetupContext *ctx, const char *uri); int (*create_account)(SipSetupContext *ctx, const char *uri, const char *passwd, const char *email, int suscribe); - int (*login_account)(SipSetupContext *ctx, const char *uri, const char *passwd); + int (*login_account)(SipSetupContext *ctx, const char *uri, const char *passwd, const char *userid); int (*get_proxy)(SipSetupContext *ctx, const char *domain, char *proxy, size_t sz); int (*get_stun_servers)(SipSetupContext *ctx, char *stun1, char *stun2, size_t size); int (*get_relay)(SipSetupContext *ctx, char *relay, size_t size); @@ -135,7 +135,7 @@ int sip_setup_context_account_exists(SipSetupContext *ctx, const char *uri); int sip_setup_context_account_validated(SipSetupContext *ctx, const char *uri); int sip_setup_context_create_account(SipSetupContext *ctx, const char *uri, const char *passwd, const char *email, int suscribe); int sip_setup_context_get_capabilities(SipSetupContext *ctx); -int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd); +int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid); int sip_setup_context_get_proxy(SipSetupContext *ctx, const char *domain, char *proxy, size_t sz); int sip_setup_context_get_stun_servers(SipSetupContext *ctx, char *stun1, char *stun2, size_t size); int sip_setup_context_get_relay(SipSetupContext *ctx, char *relay, size_t size); diff --git a/coreapi/sipwizard.c b/coreapi/sipwizard.c index c81dabf35..8d92de9dc 100644 --- a/coreapi/sipwizard.c +++ b/coreapi/sipwizard.c @@ -197,7 +197,7 @@ static void guess_display_name(LinphoneAddress *from){ ms_free(dn); } -static int sip_wizard_do_login(SipSetupContext * ctx, const char *uri, const char *passwd){ +static int sip_wizard_do_login(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid){ LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); LinphoneCore *lc=linphone_proxy_config_get_core(cfg); LinphoneAuthInfo *auth; diff --git a/gtk/loginframe.c b/gtk/loginframe.c index bd8a8643f..8e75c4c01 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -24,8 +24,8 @@ void test_button_clicked_cb(GtkWidget *button); void linphone_gtk_exit_login_frame(void); -static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd){ - if (sip_setup_context_login_account(ssctx,identity,passwd)==0){ +static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd, const char *userid){ + if (sip_setup_context_login_account(ssctx,identity,passwd,userid)==0){ } } @@ -44,7 +44,7 @@ static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){ addr=linphone_address_new(linphone_proxy_config_get_identity(cfg)); linphone_address_set_username(addr,username); tmp=linphone_address_as_string (addr); - do_login(ssctx,tmp,NULL); + do_login(ssctx,tmp,NULL,NULL); linphone_address_destroy(addr); linphone_gtk_load_identities(); return FALSE; @@ -78,6 +78,10 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ gtk_widget_hide(linphone_gtk_get_widget(mw,"disconnect_item")); gtk_widget_hide(linphone_gtk_get_widget(mw,"main_frame")); gtk_widget_show(linphone_gtk_get_widget(mw,"login_frame")); + if (linphone_gtk_get_ui_config_int("login_needs_userid",FALSE)){ + gtk_widget_show(linphone_gtk_get_widget(mw,"userid")); + gtk_widget_show(linphone_gtk_get_widget(mw,"login_userid")); + } gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),FALSE); str=g_strdup_printf(_("Please enter login information for %s"),linphone_proxy_config_get_domain(cfg)); gtk_label_set_text(GTK_LABEL(label),str); @@ -131,6 +135,7 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ GtkWidget *mw=gtk_widget_get_toplevel(button); const char *username; const char *password; + const char *userid; char *identity; gboolean autologin; LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(mw),"login_proxy_config"); @@ -139,18 +144,20 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username"))); password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password"))); - + userid=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_userid"))); + if (username==NULL || username[0]=='\0') return; autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login"))); linphone_gtk_set_ui_config_int("automatic_login",autologin); linphone_gtk_set_ui_config("login_username",username); + linphone_gtk_set_ui_config("login_userid",userid); from=linphone_address_new(linphone_proxy_config_get_identity(cfg)); linphone_address_set_username(from,username); identity=linphone_address_as_string(from); - do_login(ssctx,identity,password); + do_login(ssctx,identity,password,userid); /*we need to refresh the identities since the proxy config may have changed.*/ linphone_gtk_load_identities(); } diff --git a/gtk/main.ui b/gtk/main.ui index 190af22a1..8be5b3555 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1634,7 +1634,7 @@ True False - 4 + 5 2 @@ -1660,8 +1660,8 @@ Internet connection: - 2 - 3 + 3 + 4 @@ -1713,8 +1713,8 @@ 1 2 - 2 - 3 + 3 + 4 @@ -1729,13 +1729,39 @@ 1 2 - 3 - 4 + 4 + 5 + + + False + UserID + + + 2 + 3 + + + + + True + + False + False + True + True + + + 1 + 2 + 2 + 3 + + From 5b78e0392561ebcfbe8009f4f9cec3818fa5e7f8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 14 Feb 2014 09:21:25 +0100 Subject: [PATCH 234/439] fix compilation problems --- gtk/main.c | 2 ++ po/POTFILES.in | 3 +++ 2 files changed, 5 insertions(+) diff --git a/gtk/main.c b/gtk/main.c index bf882fa4b..9d40f8178 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -2090,8 +2090,10 @@ static void linphone_gtk_quit(void){ quit_done=TRUE; linphone_gtk_quit_core(); linphone_gtk_uninit_instance(); +#ifndef HAVE_GTK_OSX g_object_unref(icon); icon=NULL; +#endif #ifdef HAVE_NOTIFY notify_uninit(); #endif diff --git a/po/POTFILES.in b/po/POTFILES.in index 96893ed99..988253adb 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,6 +12,7 @@ gtk/buddylookup.c gtk/setupwizard.c gtk/incall_view.c gtk/loginframe.c +gtk/config-fetching.c [type: gettext/glade]gtk/main.ui [type: gettext/glade]gtk/about.ui [type: gettext/glade]gtk/contact.ui @@ -28,6 +29,8 @@ gtk/loginframe.c [type: gettext/glade]gtk/tunnel_config.ui [type: gettext/glade]gtk/keypad.ui [type: gettext/glade]gtk/ldap.ui +[type: gettext/glade]gtk/config-uri.ui +[type: gettext/glade]gtk/provisioning-fetch.ui coreapi/linphonecore.c coreapi/misc.c coreapi/presence.c From 23bf31504a6b0cb4e79fdc66ac1f2ccf686b66b7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 14 Feb 2014 12:04:42 +0100 Subject: [PATCH 235/439] Fix possible crash if message is NULL. --- tester/remote_provisioning_tester.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 45c238d63..27cd34d89 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -23,8 +23,8 @@ #include "liblinphone_tester.h" void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { - ms_message("Configuring state = %i with message %s", status, message); - + ms_message("Configuring state = %i with message %s", status, message?message:""); + stats* counters = get_stats(lc); if (status == LinphoneConfiguringSkipped) { counters->number_of_LinphoneConfiguringSkipped++; From e41f071ca1fc99284c8f45afd9aa199ba609c4d2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 14 Feb 2014 14:13:35 +0100 Subject: [PATCH 236/439] Updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 42678c758..d471ec011 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 42678c7588aa090a9038a4845ed09e5a5f9a70d7 +Subproject commit d471ec011cbb411254da9a3dfbef0cd5976db4c7 From ff733aa500f5fef604afe30a6dc1f1011327c7ea Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 14 Feb 2014 14:48:05 +0100 Subject: [PATCH 237/439] Updated ms2 to fix tester compilation --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d471ec011..c4fd2eea1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d471ec011cbb411254da9a3dfbef0cd5976db4c7 +Subproject commit c4fd2eea1e49cb102327670a122a177e08a7f206 From 2b7bd178594e2c9d2a1ae04784f3413c6904453f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 14 Feb 2014 15:12:38 +0100 Subject: [PATCH 238/439] Fix android tester compil --- build/android/liblinphone_tester.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index 4e86e8867..1730e600c 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -10,7 +10,8 @@ common_SRC_FILES := \ upnp_tester.c \ eventapi_tester.c \ stun_tester.c \ - flexisip_tester.c + flexisip_tester.c \ + remote_provisioning_tester.c common_C_INCLUDES += \ $(LOCAL_PATH) \ From 2d26dc547f143ff68bc8b9d2f88ff43d3288a48d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 14 Feb 2014 15:15:54 +0100 Subject: [PATCH 239/439] fix some bugs, update translations --- coreapi/linphonecore.c | 9 +- coreapi/siplogin.c | 1 + gtk/config-fetching.c | 4 +- gtk/linphone.h | 3 +- gtk/loginframe.c | 23 +- gtk/main.c | 2 +- gtk/setupwizard.c | 44 +- po/cs.po | 910 +++++++++++++++++++++++-------------- po/de.po | 914 +++++++++++++++++++++++-------------- po/es.po | 909 +++++++++++++++++++++++-------------- po/fr.po | 919 ++++++++++++++++++++++--------------- po/he.po | 899 +++++++++++++++++++++++-------------- po/hu.po | 910 +++++++++++++++++++++++-------------- po/it.po | 893 ++++++++++++++++++++++-------------- po/ja.po | 893 ++++++++++++++++++++++-------------- po/nb_NO.po | 897 +++++++++++++++++++++++-------------- po/nl.po | 946 ++++++++++++++++++++++++--------------- po/pl.po | 891 ++++++++++++++++++++++-------------- po/pt_BR.po | 865 +++++++++++++++++++++-------------- po/ru.po | 917 ++++++++++++++++++++++--------------- po/sr.po | 888 ++++++++++++++++++++++-------------- po/sv.po | 893 ++++++++++++++++++++++-------------- po/zh_CN.po | 887 ++++++++++++++++++++++-------------- po/zh_TW.po | 883 ++++++++++++++++++++++-------------- tester/flexisip_tester.c | 39 ++ 25 files changed, 9612 insertions(+), 5827 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b589c17b0..be3107b01 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -643,9 +643,10 @@ static void sip_config_read(LinphoneCore *lc) linphone_core_enable_ipv6(lc,ipv6); memset(&tr,0,sizeof(tr)); - tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",0); - tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",0); - tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",0); + tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",5060); + tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",5060); + /*we are not listening inbound connection for tls, port has no meaning*/ + tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",LC_SIP_TRANSPORT_RANDOM); certificates_config_read(lc); /*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/ @@ -3416,7 +3417,7 @@ int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char }else{ ms_error("Bad state for call redirection."); return -1; - } + } return 0; } diff --git a/coreapi/siplogin.c b/coreapi/siplogin.c index b70f50f0e..f10c98a60 100644 --- a/coreapi/siplogin.c +++ b/coreapi/siplogin.c @@ -80,6 +80,7 @@ static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char static int sip_login_do_logout(SipSetupContext * ctx){ LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx); + linphone_proxy_config_edit(cfg); linphone_proxy_config_enable_register(cfg,FALSE); linphone_proxy_config_done(cfg); return 0; diff --git a/gtk/config-fetching.c b/gtk/config-fetching.c index 7d6be5d07..bc7a44336 100644 --- a/gtk/config-fetching.c +++ b/gtk/config-fetching.c @@ -21,11 +21,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" -void linphone_gtk_set_configuration_uri(GtkWidget *item){ +void linphone_gtk_set_configuration_uri(void){ GtkWidget *w=linphone_gtk_create_window("config-uri"); GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); const char *uri=linphone_core_get_provisioning_uri(linphone_gtk_get_core()); - gtk_entry_set_text(GTK_ENTRY(entry),uri); + if (uri) gtk_entry_set_text(GTK_ENTRY(entry),uri); gtk_widget_show(w); } diff --git a/gtk/linphone.h b/gtk/linphone.h index c1d4323ca..7c85367bc 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -153,7 +153,7 @@ void linphone_gtk_update_video_button(LinphoneCall *call); typedef float (*get_volume_t)(void *data); void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data); -void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg); +void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login); void linphone_gtk_exit_login_frame(void); void linphone_gtk_set_ui_config(const char *key, const char *value); @@ -167,6 +167,7 @@ void linphone_gtk_unmonitor_usb(void); gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); void linphone_gtk_schedule_restart(void); +void linphone_gtk_set_configuration_uri(void); GtkWidget * linphone_gtk_show_config_fetching(void); void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state); diff --git a/gtk/loginframe.c b/gtk/loginframe.c index 8e75c4c01..7b6bd0c2b 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -37,8 +37,7 @@ static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){ if (ssctx==NULL) return TRUE;/*not ready ?*/ username=linphone_gtk_get_ui_config ("login_username",NULL); if (username==NULL) { - linphone_gtk_set_ui_config_int("automatic_login",0); - linphone_gtk_show_login_frame(cfg); + linphone_gtk_show_login_frame(cfg,TRUE); return FALSE; } addr=linphone_address_new(linphone_proxy_config_get_identity(cfg)); @@ -50,7 +49,7 @@ static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){ return FALSE; } -void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ +void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *label=linphone_gtk_get_widget(mw,"login_label"); const LinphoneAuthInfo *ai; @@ -58,13 +57,16 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ LinphoneAddress *from; LinphoneCore *lc=linphone_gtk_get_core(); const char *passwd=NULL; - + const char *userid=NULL; + gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0); - if (linphone_gtk_get_ui_config_int("automatic_login",0) ){ + if (auto_login && !disable_auto_login){ g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg); return; } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login")),auto_login); + { const char *login_image=linphone_gtk_get_ui_config("login_image","linphone-banner.png"); if (login_image){ @@ -100,9 +102,14 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ if (linphone_address_get_username(from)[0]!='?') gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")), linphone_address_get_username(from)); - if (ai) passwd=linphone_auth_info_get_passwd(ai); + if (ai) { + passwd=linphone_auth_info_get_passwd(ai); + userid=linphone_auth_info_get_userid(ai); + } gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password")), passwd!=NULL ? passwd : ""); + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_userid")), + userid ? userid : ""); linphone_address_destroy(from); } @@ -123,8 +130,7 @@ void linphone_gtk_logout_clicked(){ SipSetupContext *ss=linphone_proxy_config_get_sip_setup_context(cfg); if (ss){ sip_setup_context_logout(ss); - linphone_gtk_set_ui_config_int("automatic_login",FALSE); - linphone_gtk_show_login_frame(cfg); + linphone_gtk_show_login_frame(cfg,TRUE); } } } @@ -152,7 +158,6 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){ autologin=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login"))); linphone_gtk_set_ui_config_int("automatic_login",autologin); linphone_gtk_set_ui_config("login_username",username); - linphone_gtk_set_ui_config("login_userid",userid); from=linphone_address_new(linphone_proxy_config_get_identity(cfg)); linphone_address_set_username(from,username); diff --git a/gtk/main.c b/gtk/main.c index 9d40f8178..01fae0025 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1874,7 +1874,7 @@ void linphone_gtk_manage_login(void){ if (cfg){ SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg); if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){ - linphone_gtk_show_login_frame(cfg); + linphone_gtk_show_login_frame(cfg,FALSE); } } } diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c index afb543a85..7ea6c3295 100644 --- a/gtk/setupwizard.c +++ b/gtk/setupwizard.c @@ -43,13 +43,17 @@ static GtkWidget *create_setup_signin_choice(){ GtkWidget *t1=gtk_radio_button_new_with_label(NULL,_("Create an account on linphone.org")); GtkWidget *t2=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(t1),_("I have already a linphone.org account and I just want to use it")); GtkWidget *t3=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(t1),_("I have already a sip account and I just want to use it")); + GtkWidget *t4=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(t1),_("I want to specify a remote configuration URI")); + gtk_box_pack_start (GTK_BOX (vbox), t1, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (vbox), t2, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (vbox), t3, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (vbox), t4, TRUE, TRUE, 2); gtk_widget_show_all(vbox); g_object_set_data(G_OBJECT(vbox),"create_account",t1); g_object_set_data(G_OBJECT(vbox),"setup_linphone_account",t2); g_object_set_data(G_OBJECT(vbox),"setup_account",t3); + g_object_set_data(G_OBJECT(vbox),"config-uri",t4); return vbox; } @@ -434,26 +438,33 @@ static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page linphone_core_add_auth_info(linphone_gtk_get_core(),info); g_free(username); + // If account created on sip.linphone.org, we configure linphone to use TLS by default + if (strcmp(creator->domain, "sip:sip.linphone.org") == 0 && linphone_core_sip_transport_supported(linphone_gtk_get_core(),LinphoneTransportTls)) { + LinphoneAddress *addr=linphone_address_new(creator->domain); + char *tmp; + linphone_address_set_transport(addr, LinphoneTransportTls); + tmp=linphone_address_as_string(addr); + linphone_proxy_config_set_server_addr(cfg,tmp); + linphone_proxy_config_set_route(cfg,tmp); + ms_free(tmp); + linphone_address_destroy(addr); + } + if (linphone_core_add_proxy_config(linphone_gtk_get_core(),cfg)==-1) return; linphone_core_set_default_proxy(linphone_gtk_get_core(),cfg); linphone_gtk_load_identities(); - // If account created on sip.linphone.org, we configure linphone to use TLS by default - g_warning("Domain : %s", creator->domain); - if (strcmp(creator->domain, "sip:sip.linphone.org") == 0) { - LCSipTransports tr; - LinphoneCore* lc = linphone_gtk_get_core(); - linphone_core_get_sip_transports(lc,&tr); - tr.tls_port = tr.udp_port + tr.tcp_port + tr.tls_port; - tr.udp_port = 0; - tr.tcp_port = 0; - linphone_core_set_sip_transports(lc,&tr); - } + } } +static gint destroy_assistant(GtkWidget* w){ + gtk_widget_destroy(w); + return FALSE; +} + static int linphone_gtk_assistant_forward(int curpage, gpointer data){ GtkWidget *w=(GtkWidget*)data; GtkWidget *box=gtk_assistant_get_nth_page(GTK_ASSISTANT(w),curpage); @@ -461,6 +472,7 @@ static int linphone_gtk_assistant_forward(int curpage, gpointer data){ GtkWidget *create_button=(GtkWidget*)g_object_get_data(G_OBJECT(box),"create_account"); GtkWidget *setup_linphone_account=(GtkWidget*)g_object_get_data(G_OBJECT(box),"setup_linphone_account"); GtkWidget *setup_account=(GtkWidget*)g_object_get_data(G_OBJECT(box),"setup_account"); + GtkWidget *config_uri=(GtkWidget*)g_object_get_data(G_OBJECT(box),"config-uri"); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(create_button))) { curpage += 3; // Going to P33 @@ -471,6 +483,13 @@ static int linphone_gtk_assistant_forward(int curpage, gpointer data){ else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(setup_account))) { curpage += 1; // Going to P31 } + else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_uri))) { + /*destroy the assistant and popup config-uri dialog*/ + gtk_widget_hide(w); + linphone_gtk_set_configuration_uri(); + curpage=0; + g_idle_add((GSourceFunc)destroy_assistant,w); + } } else if (curpage == 2) { // Account's informations entered LinphoneAccountCreator *c=linphone_gtk_assistant_get_creator(w); @@ -541,7 +560,7 @@ static LinphoneAccountCreator *linphone_gtk_assistant_get_creator(GtkWidget*w){ void linphone_gtk_close_assistant(void){ if(the_assistant==NULL) return; - gtk_widget_destroy(the_assistant); + gtk_widget_destroy(the_assistant); the_assistant = NULL; } @@ -550,6 +569,7 @@ void linphone_gtk_show_assistant(void){ return; GtkWidget *w=the_assistant=gtk_assistant_new(); gtk_window_set_resizable (GTK_WINDOW(w), FALSE); + gtk_window_set_title(GTK_WINDOW(w),_("SIP account configuration assistant")); ok = create_pixbuf(linphone_gtk_get_ui_config("ok","ok.png")); notok = create_pixbuf(linphone_gtk_get_ui_config("notok","notok.png")); diff --git a/po/cs.po b/po/cs.po index 4c1cb6503..bfbfe77b8 100644 --- a/po/cs.po +++ b/po/cs.po @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone-3.5.99.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2013-05-01 09:55+0200\n" "Last-Translator: Petr Pisar \n" "Language-Team: Czech \n" @@ -28,12 +28,12 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "Volat komu: %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Poslat text komu: %s" @@ -111,35 +111,35 @@ 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:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "Neplatný sipový kontakt!" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 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:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "Soubor, kam zapisovat protokol." -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "Spustí linphone se zakázaným obrazem." -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 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:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "Zavolá právě teď na tuto adresu" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "je-li nastaveno, automaticky zvedne příchozí hovor" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -147,12 +147,17 @@ msgstr "" "Zadejte pracovní adresář (měl by být základní instalační adresář, například " "c:\\Program Files\\Linphone)" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Potvrzení" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Hovor s %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -165,68 +170,68 @@ msgstr "" "do svého adresáře?\n" "Odpovíte-li ne, tato osobo bude dočasně blokována." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Prosím, zadejte heslo pro uživatele %s\n" "v doméně %s:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 msgid "Call error" msgstr "Chyba hovoru" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Hovor ukončen" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Odpovědět" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Odmítnout" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 msgid "Call paused" msgstr "Hovor odložen" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, c-format msgid "by %s" msgstr "kým: %s" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s navrhuje začít videohovor. Přijímáte?" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Odkaz na webovou stránku" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Lipnhone – internetový videofon" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (Výchozí)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "Byly jsme přepojeni na %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -234,170 +239,171 @@ 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "Volný SIP videofon" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "Přidat do adresáře" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Stav" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Jméno" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 msgid "Call" msgstr "Zavolat" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "Diskuze" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Hledat v adresáři %s" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Upravit kontakt „%s“" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Odstranit kontakt „%s“" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, c-format msgid "Delete chat history of '%s'" msgstr "Odstranit historii diskuze u kontaktu „%s“" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Přidat nový kontakt z adresáře %s" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Kmitočet (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Stav" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Min. rychlost (kb/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parametry" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Povoleno" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Zakázáno" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Účet" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "angličtina" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "francouzština" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "švédština" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "italština" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "španělština" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "brazilská portugalština" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "polština" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "němčina" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "ruština" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "japonština" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "dánština" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "maďarština" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "čeština" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "čínština" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "tradiční čínština" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "norština" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "hebrejština" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "srbština" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 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 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "Žádné" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "ZRTP" @@ -462,59 +468,63 @@ msgstr "Účet na linphone.org již mám a chci jej použít" msgid "I have already a sip account and I just want to use it" msgstr "SIP účet již mám a chci jej použít" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "Zadejte uživatelské jméno na linphone.org" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Uživatelské jméno:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Heslo:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "Zadejte údaje o vašem účtu" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 msgid "Username*" msgstr "Uživatelské jméno*" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 msgid "Password*" msgstr "Heslo*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "Doména*" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "Proxy" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "(*) Povinné položky" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 msgid "Username: (*)" msgstr "Uživatelské jméno: (*)" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 msgid "Password: (*)" msgstr "Heslo: (*)" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "E-mail: (*)" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "Potvrďte heslo: (*)" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." @@ -523,11 +533,11 @@ msgstr "" "není dostupný).\n" "Prosím, vraťte se a zkoste to znovu." -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Děkujeme vám. Váš účet je nyní nastaven a připraven k použití." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" @@ -537,35 +547,40 @@ msgstr "" "zaslali e-mailem.\n" "Pak se sem vraťte a stiskněte tlačítko Další." -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Průvodce nastavením účtu" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Vítejte v průvodci nastavení účtu" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Průvodce nastavením účtu" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "Nastavit účet (krok 1/1)" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "Zadejte vaše sipové uživatelské jméno (krok 1/1)" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "Zadejte údaje o účtu (krok 1/2)" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "Ověření (krok 2/2)" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "Chyba" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "Ukončuje se" @@ -631,7 +646,7 @@ msgstr "UPnP selhalo" msgid "Direct or through server" msgstr "Přímé nebo skrze server" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" @@ -640,110 +655,115 @@ msgstr "" "příchozí: %f\n" "odchozí: %f (kb/s)" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "%.3f sekund" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Zavěsit" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "Volá se…" -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "dobrá" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "průměrná" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "slabá" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "velmi slabá" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "příliš špatná" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "nedostupná" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "Zabezpečeno pomocí SRTP" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Zabezpečeno pomocí ZRTP – [ověřovací klíč: %s]" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "Nastavit na neověřeno" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Nastavit na ověřeno" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "Probíhá konference" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "Probíhá hovor" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "Odložený hovor" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Hovor skončil." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "Probíhá přepojení" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "Přepojení dokončeno." -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 msgid "Transfer failed." msgstr "Přepojení selhalo." -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "Obnovit" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Odložit" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" @@ -752,15 +772,25 @@ msgstr "" "Nahrává se do\n" "%s %s" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "(Odloženo)" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Prosím, zadejte své přihlašovací jméno pro %s:" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Příchozí hovor od %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Jméno volaného" @@ -806,89 +836,90 @@ msgid "_Options" msgstr "V_olby" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Konfigurace proxy a registrace" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "Vždy spustit obraz" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Zobrazovat sám sebe" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "Nápo_věda" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "Zobrazit ladicí okno" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "_Domovská stránka" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "Vyhledat akt_ualizace" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "Průvodce účtem" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "SIP adresa nebo telefonní číslo:" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "Zahájit nový hovor" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "Kontakty" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Přidat" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Upravit" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Hledat" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "Přidat kontakty z adresáře" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "Přidat kontakt" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Recent calls" msgstr "Nedávné hovory" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Moje současná totožnost:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Uživatelské jméno" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Heslo" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Připojení k Internetu:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Přihlašovat mě automaticky" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "Identifikátor uživatele" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Informace o přihlášení" @@ -934,6 +965,7 @@ msgid "An internet video phone using the standard SIP (rfc3261) protocol." msgstr "Internetový videofon používající standardní protokol SIP (RFC 3261)." #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -946,6 +978,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat a Delphine Perreau\n" @@ -991,10 +1024,6 @@ msgstr "Linphone – Ověření totožnosti vyžadováno" msgid "Please enter the domain password" msgstr "Prosím, zadejte heslo pro doménu" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Identifikátor uživatele" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Historie volání" @@ -1032,271 +1061,317 @@ msgid "Looks like sip:" msgstr "Vypadá jako sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Směrování (volitelné):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Registrační období (s):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Směrování (volitelné):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Směrování (volitelné):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Přenos" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "Zaregistrovat se" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Zveřejnit stav přítomnosti" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "Nastavit SIP účet" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "implicitní zvuková karta" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "zvuková karta" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "implicitní kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Kodeky zvuku" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Kodeky obrazu" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "C" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "SIP (TCP)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "SIP (TLS)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Nastavení" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Nastavit MTU (největší přenositelná zpráva):" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "Odesílat tóny DTMF jako SIP INFO zprávy" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "Používat IPv6 místo IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Přenos" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "Druh šifrování médií" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "Obrazový RTP/UDP:" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "Zvukový RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "Položky DSCP" - # Port number -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "Stálý" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "Tunel" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "Šifrování médií je povinné" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "Tunel" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "Položky DSCP" + +#: ../gtk/parameters.ui.h:26 +#, fuzzy +msgid "SIP/TCP port" +msgstr "SIP port" + +#: ../gtk/parameters.ui.h:27 +#, fuzzy +msgid "SIP/UDP port" +msgstr "SIP port" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "Síťové protokoly a porty" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Přímé připojení do Internetu" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "Za NAT/firewallem (adresu brány zadejte níže)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Veřejná IP adresa:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Za NAT/firewallem (adresu určí STUN)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 msgid "Behind NAT / Firewall (use ICE)" msgstr "Za NAT/firewallem (adresu určí ICE)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 msgid "Behind NAT / Firewall (use uPnP)" msgstr "Za NAT/firewallem (adresu určí UPnP)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Veřejná IP adresa:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "STUN server:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT a firewall" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Nastavení sítě" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Vyzvánění:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "Zvláštní ALSA zařízení (volitelné):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Zařízení pro nahrávání:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Zařízení pro vyzvánění:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Zařízení pro přehrávání:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Zapnout potlačení ozvěny" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Zvuk" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Vstupní zařízení obrazu:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Upřednostňované rozlišení obrazu:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Vstupní zařízení obrazu:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Obraz" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Nastavení multimédií" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "Tento oddíl určuje vaši SIP adresu, když se nepoužívá žádný účet" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Vaše zobrazované jméno (např. Jan Novák):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Vaše uživatelské jméno:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Vaše výsledná SIP adresa:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Implicitní totožnost" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "Průvodce" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Přidat" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Upravit" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Odstranit" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Proxy účty" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Vymazat všechna hesla" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Soukromí" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "Nastavení SIP účtů" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Povolit" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Zakázat" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Kodeky" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 znamená „neomezeno“" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Omezení odchozí rychlosti (kb/s):" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Omezení příchozí rychlosti (kb/s):" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "Zapnout přizpůsobující se řízení rychlosti" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1304,31 +1379,54 @@ msgstr "" "Přizpůsobující se řízení rychlosti je technika dynamického odhadu " "dostupného pásma během hovoru." -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Využití šířky pásma" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "Kodeky" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Jazyk" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Zobrazit podrobnější nastavení" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "Úroveň" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Uživatelské rozhraní" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Adresa serveru:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Selhání ověření totožnosti" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Proxy účty" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Hotovo" @@ -1353,7 +1451,8 @@ msgid "Please wait" msgstr "Prosím, čekejte" #: ../gtk/dscp_settings.ui.h:1 -msgid "Dscp settings" +#, fuzzy +msgid "DSCP settings" msgstr "Nastavení DSCP" #: ../gtk/dscp_settings.ui.h:2 @@ -1405,6 +1504,15 @@ msgid "Round trip time" msgstr "Odezva" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Upřednostňované rozlišení obrazu:" + +#: ../gtk/call_statistics.ui.h:11 msgid "Call statistics and information" msgstr "Statistické a ostatní údaje o hovoru" @@ -1488,19 +1596,142 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:227 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Nastavení" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "UPnP není nedostupné" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Kodeky" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +#, fuzzy +msgid "Realm" +msgstr "doména:" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Zvuk" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "SIP adresa" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Hledat někoho" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Různé" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Připojuje se…" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "přerušen" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "dokončen" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "promeškán" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1515,102 +1746,77 @@ msgstr "" "Stav: %s\n" "Délka: %i min %i s\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Odchozí hovor" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Připraven." -#: ../coreapi/linphonecore.c:2184 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Potvrzení" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Vyhledává se umístění čísla…" -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Toto číslo nelze vyhledat." -#: ../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:2432 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Navazuje se spojení" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "Nelze volat" -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2765 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:2952 msgid "is contacting you" msgstr "vás volá" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr " a požaduje automatickou zvednutí." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "Upravují se parametry hovoru…" -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Připojeno." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "Hovor přerušen" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "Hovor nebylo možné odložit" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "Současný hovor se odkládá…" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Váš počítač používá zvukový ovladač ALSA. Jde o nejlepší\n" -"volbu. Linphone však potřebuje ke své práci modul emulace\n" -"oss, který chybí. Prosím zadejte jako uživatel root příkaz\n" -"'modprobe snd-pcm-oss', kterým modul zavede." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Váš počítač používá zvukový ovladač ALSA. Jde o nejlepší\n" -"volbu. Linphone však potřebuje ke své práci modul mixer emulace\n" -"oss, který chybí. Prosím zadejte jako uživatel root příkaz\n" -"'modprobe snd-mixer-oss', kterým modul zavede." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "Hledá se adresa pomocí STUN…" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "Shromažďují se místní kandidáti ICE…" @@ -1659,10 +1865,15 @@ msgid "Pending" msgstr "Čekám" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Délka" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Neznámá chyba" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1670,7 +1881,7 @@ msgstr "" "Adresa SIP proxy, kterou jste zadali, není platná. Musí začínat na „sip:“ a " "pak musí následovat jméno stroje." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1678,124 +1889,128 @@ 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:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "Nelze se přihlásit jako %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "Vyzvání na druhé straně." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "Vyzvání na druhé straně…" -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "Časná média." -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "Hovor s %s je odložen." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "Hovor přijat kým: %s – odložen." -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "Hovor obnoven." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "Hovor přijat kým: %s." -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "Není slučitelné. Zkontrolujte nastavení kodeků a zabezpečení…" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "Byli jsme obnoveni." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "Byli jsme odloženi protistranou." -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "Hovor byl aktualizován protistranou." -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Hovor ukončen." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Uživatel je zaneprázdněn." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Uživatel je dočasně nedostupný." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "Uživatel si nepřeje být rušen." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Volání odmítnuto." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "Žádná odpověď." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "Chyba protokolu." -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "Přesměrováno" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "Neslučitelné parametry médií." -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "Volání se nezdařilo." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Registrace na %s byla úspěšná." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "Odregistrování z %s hotovo." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "odpověď nedorazila včas" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrace na %s selhala: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, c-format msgid "Authentication token is %s" msgstr "Klíč k ověření totožnosti je %s" -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1803,6 +2018,34 @@ msgstr[0] "Máte %i zmeškaný hovor." msgstr[1] "Máte %i zmeškané hovory." msgstr[2] "Máte %i zmeškaných hovorů." +#~ msgid "" +#~ "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 " + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Váš počítač používá zvukový ovladač ALSA. Jde o nejlepší\n" +#~ "volbu. Linphone však potřebuje ke své práci modul emulace\n" +#~ "oss, který chybí. Prosím zadejte jako uživatel root příkaz\n" +#~ "'modprobe snd-pcm-oss', kterým modul zavede." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Váš počítač používá zvukový ovladač ALSA. Jde o nejlepší\n" +#~ "volbu. Linphone však potřebuje ke své práci modul mixer emulace\n" +#~ "oss, který chybí. Prosím zadejte jako uživatel root příkaz\n" +#~ "'modprobe snd-mixer-oss', kterým modul zavede." + #~ msgid "by %s" #~ msgstr "kým: %s" @@ -1836,9 +2079,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "Verifying" #~ msgstr "Ověřování" -#~ msgid "Confirmation" -#~ msgstr "Potvrzení" - #~ msgid "Creating your account" #~ msgstr "Vytváření účtu" @@ -1871,9 +2111,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "No common codecs" #~ msgstr "Žádný společný formát" -#~ msgid "Authentication failure" -#~ msgstr "Selhání ověření totožnosti" - #~ msgid "Register at startup" #~ msgstr "Zaregistrovat při spuštění" @@ -2136,9 +2373,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "Call answered - connected." #~ msgstr "Hovoř přijat – spojen." -#~ msgid "Incoming call from %s" -#~ msgstr "Příchozí hovor od %s" - #~ msgid "Assistant" #~ msgstr "Průvodce" @@ -2241,9 +2475,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "Unknown" #~ msgstr "Stav není znám" -#~ msgid "SIP address" -#~ msgstr "SIP adresa" - #~ msgid "Bresilian" #~ msgstr "brazilská portugalština" @@ -2272,9 +2503,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "Use the supplied stun server above and do as best as possible" #~ msgstr "Použij výše zadaný STUN server a snaž se, jak nejlépe umíš" -#~ msgid "Miscelaneous" -#~ msgstr "Různé" - #~ msgid "Go" #~ msgstr "Soubor" @@ -2498,9 +2726,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "Je doporučeno používat port 5060." -#~ msgid "SIP port" -#~ msgstr "SIP port" - #~ msgid "@" #~ msgstr "@" @@ -2544,9 +2769,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "None." #~ msgstr "Žádné." -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Konfigurace proxy a registrace" - #~ msgid "Send registration:" #~ msgstr "Odeslat registraci:" @@ -2574,9 +2796,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "userid:" #~ msgstr "ID uživatele:" -#~ msgid "realm:" -#~ msgstr "doména:" - #~ msgid "Text:" #~ msgstr "Text:" @@ -2653,9 +2872,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "Connection type:" #~ msgstr "Typ připojení:" -#~ msgid "Server address" -#~ msgstr "Adresa serveru:" - #~ msgid "" #~ "Linphone could not open audio device %s. Check if your sound card is " #~ "fully configured and working." diff --git a/po/de.po b/po/de.po index 855048c94..95a385def 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2012-11-07 19:27+0100\n" "Last-Translator: Gerhard Stengel \n" "Language-Team: German \n" @@ -17,12 +17,12 @@ msgstr "" "X-Generator: Lokalize 1.5\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "„%s“ anrufen" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Text zu „%s“ schicken" @@ -96,37 +96,37 @@ msgstr "Eigenes Telefon" msgid "Couldn't find pixmap file: %s" msgstr "Pixmapdatei %s kann nicht gefunden werden." -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "Ungültiger SIP-Kontakt!" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "Ausgabe von Debug-Informationen auf stdout während der Laufzeit" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "Pfad zu einer Datei, in die Protokolle geschrieben werden." -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "Linphone mit ausgeschaltetem Video starten." -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 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:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "Im Moment anzurufende Adresse" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "Falls aktiviert, werden eingehende Anrufe automatisch beantwortet" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -134,12 +134,17 @@ msgstr "" "Geben Sie einen Arbeitsordner an (sollte der Installationsordner sein, z. B. " "C:\\Programme\\Linphone)" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Bestätigung" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Im Gespräch mit %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -152,68 +157,68 @@ msgstr "" "Ihrer Kontaktliste hinzufügen?\n" "Wenn Sie mit Nein antworten, wird diese Person vorläufig blockiert." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Geben Sie bitte Ihr Passwort für den Benutzernamen %s\n" " auf der Domäne %s ein:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 msgid "Call error" msgstr "Anruf fehlgeschlagen" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Anruf beendet" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Annehmen" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Abweisen" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 msgid "Call paused" msgstr "Anruf wird gehalten" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, c-format msgid "by %s" msgstr "von %s" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, 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:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Website-Verknüpfung" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - ein Internet-Video-Telefon" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (Vorgabe)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "Vermittlung nach %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -221,172 +226,173 @@ msgstr "" "Auf diesem Rechner können keine Soundkarten gefunden werden.\n" "Sie können keine Audio-Anrufe tätigen oder entgegennehmen." -#: ../gtk/main.c:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "Ein freies SIP-Video-Telefon" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "Zum Adressbuch hinzufügen" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Anwesenheitsstatus" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Name" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 msgid "Call" msgstr "Anrufen" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 #, fuzzy msgid "Chat" msgstr "Chat Raum" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Im %s-Verzeichnis suchen" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Kontakt „%s“ bearbeiten" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Kontakt „%s“ löschen" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Kontakt „%s“ löschen" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Einen neuen Kontakt aus dem %s-Verzeichnis hinzufügen" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Rate (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Min. Bitrate (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parameter" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Freigegeben" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Gesperrt" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "Englisch" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Französisch" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Schwedisch" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Italienisch" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Spanisch" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "Brasilianisches Portugiesisch" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Polnisch" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Deutsch" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Russisch" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "Japanisch" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Niederländisch" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Ungarisch" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Tschechisch" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "Chinesisch" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "Traditionelles Chinesisch" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "Norwegisch" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 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:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "Keinen" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -452,59 +458,63 @@ msgstr "" msgid "I have already a sip account and I just want to use it" msgstr "Ich habe bereits ein SIP-Konto und möchte es jetzt benutzen." -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "Geben Sie Ihren Benutzernamen bei linphone.org ein." -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Benutzername:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Passwort:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "Geben Sie Ihre Zugangsdaten ein." -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 msgid "Username*" msgstr "Benutzername*" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 msgid "Password*" msgstr "Passwort*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "Domäne*" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "Proxy" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "(*) erforderliche Felder" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 msgid "Username: (*)" msgstr "Benutzername: (*)" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 msgid "Password: (*)" msgstr "Passwort: (*)" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "E-Mail: (*)" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "Bestätigen Sie Ihr Passwort: (*)" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." @@ -513,12 +523,12 @@ msgstr "" "verwendet oder der Server ist unerreichbar.\n" "Bitte gehen Sie zurück und versuchen Sie es noch einmal." -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "" "Danke. Ihr Konto ist nun fertig eingerichtet und kann verwendet werden." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" @@ -528,35 +538,40 @@ msgstr "" "wir Ihnen soeben per E-Mail geschickt haben.\n" "Danach gehen Sie hierher zurück und drücken auf „Vor“." -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Konto-Einrichtungsassistent" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Willkommen zum Konto-Einrichtungsassistenten" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Konto-Einrichtungsassistent" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "Konto einrichten (Schritt 1/1)" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "Geben Sie Ihren SIP-Benutzernamen ein (Schritt 1/1)" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "Geben Sie Ihre Zugangsdaten ein (Schritt 1/2)" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "Bestätigung (Schritt 2/2)" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "Fehler" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "Fertigstellen" @@ -626,7 +641,7 @@ msgstr "ICE fehlgeschlagen" msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" @@ -635,126 +650,141 @@ msgstr "" "Herunterladen: %f\n" "Hochladen: %f (kbit/s)" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, fuzzy, c-format msgid "%.3f seconds" msgstr "%i Sekunde" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "Verbindungsaufbau..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "gut" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "durchschnittlich" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "schlecht" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "sehr schlecht" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "zu schlecht" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "nicht verfügbar" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "Gesichert durch SRTP" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Gesichert durch ZRTP - [Auth.-Token: %s]" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "Auf „Ungeprüft“ setzen" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Auf „Geprüft“ setzen" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "In Konferenz" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "Im Gespräch" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "Gehaltener Anruf" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Anruf beendet." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "Vermittlung läuft" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "Vermittlung abgeschlossen." -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 msgid "Transfer failed." msgstr "Vermittlung fehlgeschlagen." -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "Fortsetzen" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Halten" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, fuzzy msgid "(Paused)" msgstr "Halten" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Bitte geben Sie die Anmeldeinformationen für %s ein." +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Eingehendes Gespr�h" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Name des Angerufenen" @@ -801,89 +831,90 @@ msgid "_Options" msgstr "_Optionen" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Proxy/Registrator Konfigurationsbox" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "Video immer starten" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Selbstansicht ein" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "_Hilfe" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "Debug-Fenster anzeigen" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "Auf _Aktualisierungen überprüfen" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "Konto-Einrichtungsassistent" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "SIP-Adresse oder Telefonnummer:" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "Einen neuen Anruf beginnen" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "Kontakte" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Hinzufügen" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Bearbeiten" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Suchen" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "Kontakte aus einem Verzeichnis hinzufügen" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "Kontakt hinzufügen" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Recent calls" msgstr "Letzte Gespräche" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Aktuelle Identität:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Benutzername" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Passwort" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Internetverbindung:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Automatisch anmelden" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "Benutzer-ID" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Anmeldeinformationen" @@ -931,6 +962,7 @@ msgstr "" "verwendet." #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -943,6 +975,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -989,10 +1022,6 @@ msgstr "Linphone - Authentifikation erforderlich" msgid "Please enter the domain password" msgstr "Bitte das Passwort der Domäne eingeben" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Benutzer-ID" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Anrufchronik" @@ -1030,274 +1059,320 @@ msgid "Looks like sip:" msgstr "Sieht aus wie sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (optional):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Registrierungsdauer (sec):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Route (optional):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Route (optional):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Übertragung" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "Registrieren" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Anwesenheitsstatus veröffentlichen" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "SIP-Konto einrichten" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "Standard-Soundkarte" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "eine Soundkarte" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "Standard-Kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Audio-Codecs" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Video-Codecs" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Einstellungen" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Maximum Transmission Unit setzen:" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "DTMFs als SIP-Info senden" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "IPv6 statt IPv4 verwenden" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Übertragung" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "Verschlüsselungstyp der Medien" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "DSCP-Felder" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "Fest" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "Tunnel" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 #, fuzzy msgid "Media encryption is mandatory" msgstr "Verschlüsselungstyp der Medien" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "Tunnel" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "DSCP-Felder" + +#: ../gtk/parameters.ui.h:26 +#, fuzzy +msgid "SIP/TCP port" +msgstr "SIP-Port" + +#: ../gtk/parameters.ui.h:27 +#, fuzzy +msgid "SIP/UDP port" +msgstr "SIP-Port" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "Netzwerkprotokoll und Ports" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Direkte Verbindung ins Internet" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "Hinter NAT / Firewall (IP-Gateway darunter angeben)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Öffentliche IP-Adresse:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Hinter NAT / Firewall (STUN verwenden)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 msgid "Behind NAT / Firewall (use ICE)" msgstr "Hinter NAT / Firewall (ICE verwenden)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "Hinter NAT / Firewall (ICE verwenden)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Öffentliche IP-Adresse:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "STUN-Server:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT und Firewall" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Netzwerkeinstellungen" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Klingelton:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "Spezielles ALSA-Gerät (optional):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Aufnahmegerät:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Gerät für Klingelton:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Wiedergabegerät:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Echounterdrückung ein" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Audio" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Video-Aufnahmegerät:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Bevorzugte Video-Auflösung:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Video-Aufnahmegerät:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Video" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Multimedia-Einstellungen" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" "In diesem Bereich legen Sie Ihre SIP-Adresse fest, wenn Sie kein SIP-Konto " "verwenden." -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Ihr angezeigter Name (z. B. Heinz Müller):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Ihr Benutzername:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Sich ergebende SIP-Adresse:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Standard-Identität" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "Assistent" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Hinzufügen" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Bearbeiten" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Entfernen" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Proxy-Konten" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Alle Passwörter löschen" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Privatsphäre" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "SIP-Konten verwalten" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Freigeben" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Sperren" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 bedeutet „unbegrenzt“" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Upload-Bandbreite (kbit/sec):" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Download-Bandbreite (kbit/sec):" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "Adaptive Ratenregelung ein" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1305,31 +1380,54 @@ msgstr "" "Adaptive Ratenregelung ist eine Technik zur dynamischen Abschätzung der " "zur Verfügung stehenden Bandbreite während eines Anrufs." -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Bandbreiten-Einstellungen" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Sprache" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Fortgeschrittene Einstellungen anzeigen" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "Detaillierung" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Benutzeroberfläche" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Server-Adresse:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Authentifikation fehlgeschlagen" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Proxy-Konten" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Fertig" @@ -1354,7 +1452,8 @@ msgid "Please wait" msgstr "Bitte warten" #: ../gtk/dscp_settings.ui.h:1 -msgid "Dscp settings" +#, fuzzy +msgid "DSCP settings" msgstr "DSCP-Einstellungen" #: ../gtk/dscp_settings.ui.h:2 @@ -1409,6 +1508,15 @@ msgid "Round trip time" msgstr "Audio Eigenschaften" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Bevorzugte Video-Auflösung:" + +#: ../gtk/call_statistics.ui.h:11 msgid "Call statistics and information" msgstr "Anrufstatistik und -informationen" @@ -1492,19 +1600,142 @@ msgstr "" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Einstellungen" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "nicht verfügbar" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Codecs" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +#, fuzzy +msgid "Realm" +msgstr "Bereich:" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Audio" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "Adresse" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Kontaktsuche" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Video" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Verbinden..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "abgebrochen" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "beendet" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "entgangen" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1519,103 +1750,77 @@ msgstr "" "Status: %s\n" "Dauer: %i min %i sec\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Abgehender Anruf" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Bereit" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Bestätigung" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Telefonnummernziel wird gesucht..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Diese Nummer kann nicht aufgelöst werden." -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"SIP-Adresse kann nicht eingelesen werden. Eine SIP-Adresse hat folgenden " -"Aufbau " - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Verbindungsaufbau" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "Anruf kann nicht getätigt werden." -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Die maximale Anzahl der gleichzeitigen Anrufe ist erreicht." -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "ruft Sie an" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr " und fragt nach automatischer Antwort." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "Die Anrufparameter werden verändert..." -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Verbunden." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "Anruf abgebrochen" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "Anruf kann nicht gehalten werden" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "Aktueller Anruf wird gehalten..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Ihre Rechner verwendet anscheinend einen ALSA-Soundtreiber.\n" -"Dies ist die beste Lösung; allerdings ist das von Linphone benötigte Modul\n" -"zur PCM-OSS-Emulation nicht vorhanden. Bitte führen Sie als\n" -"Systemverwalter den Befehl „modprobe snd-pcm-oss“ aus, um es zu laden." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Ihre Rechner verwendet anscheinend einen ALSA-Soundtreiber.\n" -"Dies ist die beste Lösung; allerdings ist das von Linphone benötigte Modul\n" -"zur Mixer-OSS-Emulation nicht vorhanden. Bitte führen Sie als\n" -"Systemverwalter den Befehl „modprobe snd-mixer-oss“ aus, um es zu laden." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "STUN-Ermittlung läuft..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "Lokale Kandidaten für ICE werden zusammengestellt..." @@ -1664,10 +1869,15 @@ msgid "Pending" msgstr "Ausstehend" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Dauer" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Unbekannter Fehler" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1675,7 +1885,7 @@ msgstr "" "Die von Ihnen eingegebene SIP-Proxy-Adresse ist ungültig, sie muss mit " "„sip:“ gefolgt vom Hostnamen beginnen." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1684,131 +1894,166 @@ msgstr "" "Sie sollte wie sip:benutzername@proxydomain aussehen, also z.B. sip:" "alice@beispiel.net" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "Anmeldung als %s fehlgeschlagen" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "Klingeln bei der Gegenseite." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "Klingeln bei der Gegenseite..." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "Anruf mit %s wird gehalten." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "Der von %s entgegengenommene Anruf wird gehalten." -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "Anruf fortgesetzt." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "Anruf wird von %s entgegengenommen." -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "Inkompatibel, überprüfen Sie die Codecs..." -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "Anruf wird fortgesetzt." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "Anruf wird von der Gegenseite gehalten." -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "Anruf ist von der Gegenseite aktualisiert worden." -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Anruf beendet." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Teilnehmer ist besetzt." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Teilnehmer zur Zeit nicht verfügbar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "Teilnehmer möchte nicht gestört werden." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Anruf abgewiesen" -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "Keine Antwort." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "Protokollfehler" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "Umgeleitet" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "Inkompatible Medienparameter." -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "Anruf fehlgeschlagen." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Registrierung auf %s erfolgreich." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "Abmeldung von %s ist erfolgt." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "Zeitüberschreitung bei der Antwort" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrierung auf %s fehlgeschlagen: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, c-format msgid "Authentication token is %s" msgstr "Authentifizierungs-Token ist %s" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Sie haben %i Anruf in Abwesenheit." msgstr[1] "Sie haben %i Anrufe in Abwesenheit." +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "SIP-Adresse kann nicht eingelesen werden. Eine SIP-Adresse hat folgenden " +#~ "Aufbau " + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Ihre Rechner verwendet anscheinend einen ALSA-Soundtreiber.\n" +#~ "Dies ist die beste Lösung; allerdings ist das von Linphone benötigte " +#~ "Modul\n" +#~ "zur PCM-OSS-Emulation nicht vorhanden. Bitte führen Sie als\n" +#~ "Systemverwalter den Befehl „modprobe snd-pcm-oss“ aus, um es zu laden." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Ihre Rechner verwendet anscheinend einen ALSA-Soundtreiber.\n" +#~ "Dies ist die beste Lösung; allerdings ist das von Linphone benötigte " +#~ "Modul\n" +#~ "zur Mixer-OSS-Emulation nicht vorhanden. Bitte führen Sie als\n" +#~ "Systemverwalter den Befehl „modprobe snd-mixer-oss“ aus, um es zu laden." + #~ msgid "Keypad" #~ msgstr "Wähltastatur" @@ -1840,9 +2085,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "No common codecs" #~ msgstr "Keine gemeinsamen Codecs" -#~ msgid "Authentication failure" -#~ msgstr "Authentifikation fehlgeschlagen" - #~ msgid "We are being paused..." #~ msgstr "Anruf wird gehalten..." @@ -1872,9 +2114,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "Verifying" #~ msgstr "Überprüfen" -#~ msgid "Confirmation" -#~ msgstr "Bestätigung" - #~ msgid "Creating your account" #~ msgstr "Erstellen Ihres Kontos" @@ -2143,10 +2382,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ "Linphoneverwendet normalerweise IPv4. Bitte Konfiguration anpassen wenn " #~ "sie IPv6 verwenden wollen" -#, fuzzy -#~ msgid "Incoming call from %s" -#~ msgstr "Eingehendes Gespr�h" - #, fuzzy #~ msgid "_Modes" #~ msgstr "Codecs" @@ -2220,10 +2455,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "Out To Lunch" #~ msgstr "Beim Essen" -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Adresse" - #, fuzzy #~ msgid "_View" #~ msgstr "Video" @@ -2409,9 +2640,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "Wir empfehlen, Port 5060 zu verwenden" -#~ msgid "SIP port" -#~ msgstr "SIP-Port" - #~ msgid "@" #~ msgstr "@" @@ -2461,9 +2689,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "None." #~ msgstr "Nichts." -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Proxy/Registrator Konfigurationsbox" - #~ msgid "Send registration:" #~ msgstr "Sende Registrierung:" @@ -2491,9 +2716,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "userid:" #~ msgstr "Benutzer ID:" -#~ msgid "realm:" -#~ msgstr "Bereich:" - #~ msgid "Text:" #~ msgstr "Text" @@ -2554,10 +2776,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "Firewall 's external ip address (in dot notations):" #~ msgstr "IP-Adresse des Firewall (in Punktnotation)" -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Server-Adresse:" - #~ msgid "28k modem" #~ msgstr "28K Modem" diff --git a/po/es.po b/po/es.po index 474f630f4..92bfad869 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2012-12-06 15:54+0100\n" "Last-Translator: BERAUDO Guillaume \n" "Language-Team: es \n" @@ -15,12 +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:969 #, c-format msgid "Call %s" msgstr "Llamar a %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Enviar mensaje a %s" @@ -101,36 +101,36 @@ msgstr "Yo" msgid "Couldn't find pixmap file: %s" msgstr "No se pudo encontrar el archivo pixmap: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "¡Contacto SIP no válido!" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 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:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "ruta a un fichero donde escribir logs." -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 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:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "dirección a la que llamar inmediatamente" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "si está activo, responder a llamadas entrantes automáticamente" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -138,12 +138,17 @@ 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:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Confirmación" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Llamar con %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -156,72 +161,72 @@ msgstr "" "contactos?\n" "Si responde no, esta persona será bloqueada temporalmente." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Por favor, introduzca la contraseña para el usuario %s\n" " en el dominio %s:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "Error en la llamada." -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 #, fuzzy msgid "Call ended" msgstr "Llamada terminada" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Llamada entrante" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Contestar" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "Rechazar" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "Llamada en pausa" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Puertos" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Enlace a la Web" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - un video-teléfono a través de Internet" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (Opción predeterminada)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "Somos transferidos a %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -229,173 +234,174 @@ 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "Un video-teléfono SIP gratuito" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 #, fuzzy msgid "Add to addressbook" msgstr "Añadir a la agenda" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 #, fuzzy msgid "Presence status" msgstr "Estado de Presencia" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nombre" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "Llamada" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Buscar en el directorio %s" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Editar contacto '%s'" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Eliminar contacto '%s'" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Eliminar contacto '%s'" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Añadir nuevo contacto desde el directorio %s" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Frecuencia (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Estado" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Bitrate mínimo (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parámetros" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Activado" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Desactivado" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Cuenta" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "Inglés" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Francés" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Sueco" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Italiano" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Español" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "Portugués de Brasil" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Polaco" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Alemán" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Ruso" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "Japonés" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Holandés" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Húngaro" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Checo" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "Chino" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "Chino Tradicional" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "Noruego" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 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:934 +#: ../gtk/propertybox.c:1219 #, fuzzy msgid "None" msgstr "Ninguno." -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "ZRTP" @@ -465,111 +471,120 @@ msgstr "Ya tengo una cuenta y quiero utilizarla" msgid "I have already a sip account and I just want to use it" msgstr "Ya tengo una cuenta y quiero utilizarla" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 #, fuzzy msgid "Username:" msgstr "Nombre de usuario:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 #, fuzzy msgid "Password:" msgstr "Contraseña:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "Nombre de usuario" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "Contraseña:" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "Nombre de usuario:" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "Contraseña:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Gracias. Su cuenta está configurada y lista para su utilización." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Asistente de configuración de cuenta" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Bienvenido al asistente de configuración de cuenta" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Asistente de configuración de cuenta" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Configurar una cuenta SIP" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "" @@ -641,140 +656,155 @@ msgstr "La llamada ha fallado." msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, fuzzy, c-format msgid "%.3f seconds" msgstr "%i segundo" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 #, fuzzy msgid "Calling..." msgstr " Llamando..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 #, fuzzy msgid "Incoming call" msgstr "Llamada entrante" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "buena" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "media" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "mala" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "muy mala" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "demasiado mala" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "no disponible" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "Cifrada con SRTP" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Cifrada con ZRTP - [token de autenticación: %s]" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "Set sin verificar" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Set verificado" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "En conferencia" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 #, fuzzy msgid "In call" msgstr "En llamada " -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 #, fuzzy msgid "Paused call" msgstr "Llamada en pausa" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 #, fuzzy msgid "Call ended." msgstr "Llamada finalizada." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 #, fuzzy msgid "Transfer done." msgstr "Transferir" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Transferir" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "Reanudar" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pausar" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, fuzzy msgid "(Paused)" msgstr "Pausar" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Por favor, introduzca los datos de inicio de sesión para %s" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -825,100 +855,101 @@ msgid "_Options" msgstr "_Opciones" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Confirmación" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "Enable self-view" msgstr "Activar vista propia" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "_Ayuda" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 #, fuzzy msgid "Show debug window" msgstr "Mostrar ventana de depuración" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "_Pagina_de_Inicio" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "Buscar_Actualizaciones" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "Account assistant" msgstr "Asistente de configuración de cuenta" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 #, fuzzy msgid "SIP address or phone number:" msgstr "Dirección SIP o número de teléfono" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "Iniciar nueva llamada" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 #, fuzzy msgid "Contacts" msgstr "Contactos" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Añadir" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Editar" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Buscar" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Add contacts from directory" msgstr "Añadir contactos desde un directorio" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contact" msgstr "Añadir contacto" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "Llamadas recientes " -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "My current identity:" msgstr "Mi identidad actual:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Nombre de usuario" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Contraseña:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Conexión a Internet" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Iniciar sesión automáticamente" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "UserID" + #: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" @@ -972,6 +1003,7 @@ msgstr "" "(rfc3261)" #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -984,6 +1016,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -1033,10 +1066,6 @@ msgstr "Linphone - Autenticación necesaria" msgid "Please enter the domain password" msgstr "Por favor introduzca la contraseña del dominio" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "UserID" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Registro de llamadas" @@ -1076,295 +1105,341 @@ msgid "Looks like sip:" msgstr "Del tipo sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Ruta (opcional):" - -#: ../gtk/sip_account.ui.h:8 #, fuzzy msgid "Registration duration (sec):" msgstr "Duración del registro (seg):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Ruta (opcional):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Ruta (opcional):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Transporte " + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "Registrarse" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 #, fuzzy msgid "Publish presence information" msgstr "Publicar información de presencia" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "Configurar una cuenta SIP" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "tarjeta de sonido predeterminada" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "una tarjeta de sonido" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "cámara predeterminada" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 #, fuzzy msgid "Audio codecs" msgstr "Códecs de Audio" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 #, fuzzy msgid "Video codecs" msgstr "Códecs de Vídeo" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "C" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "SIP (TCP)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "SIP (TLS)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Configuración" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Fijar Unidad de Transmisión Máxima:" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "Enviar DTMFs como información SIP" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "Utilizar IPv6 en lugar de IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 #, fuzzy msgid "Transport" msgstr "Transporte " -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "Tipo de cifrado de medios" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "Vídeo RTP/UDP" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "Audio RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 #, fuzzy msgid "Media encryption is mandatory" msgstr "Tipo de cifrado de medios" -#: ../gtk/parameters.ui.h:23 -msgid "Network protocol and ports" -msgstr "Protocolo de red y puertos" - #: ../gtk/parameters.ui.h:24 -msgid "Direct connection to the Internet" -msgstr "Conexión directa a Internet" +msgid "Tunnel" +msgstr "" #: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" -msgstr "Tras un NAT/Firewall (especificar la IP de la puerta de enlace debajo)" +msgid "DSCP fields" +msgstr "" #: ../gtk/parameters.ui.h:26 #, fuzzy -msgid "Public IP address:" -msgstr "Dirección IP pública:" +msgid "SIP/TCP port" +msgstr "Puerto SIP" #: ../gtk/parameters.ui.h:27 +#, fuzzy +msgid "SIP/UDP port" +msgstr "Puerto SIP" + +#: ../gtk/parameters.ui.h:28 +msgid "Network protocol and ports" +msgstr "Protocolo de red y puertos" + +#: ../gtk/parameters.ui.h:29 +msgid "Direct connection to the Internet" +msgstr "Conexión directa a Internet" + +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "Tras un NAT/Firewall (especificar la IP de la puerta de enlace debajo)" + +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Tras un NAT/Firewall (utilizar STUN para resolver)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 #, fuzzy msgid "Behind NAT / Firewall (use ICE)" msgstr "Tras un NAT/Firewall (utilizar STUN para resolver)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "Tras un NAT/Firewall (utilizar STUN para resolver)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +#, fuzzy +msgid "Public IP address:" +msgstr "Dirección IP pública:" + +#: ../gtk/parameters.ui.h:35 #, fuzzy msgid "Stun server:" msgstr "Servidor STUN" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 #, fuzzy msgid "NAT and Firewall" msgstr "NAT y Firewall" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 #, fuzzy msgid "Network settings" msgstr "Configuración de red" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 #, fuzzy msgid "Ring sound:" msgstr "Tono de llamada:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "Dispositivo especial ALSA (opcional):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 #, fuzzy msgid "Capture device:" msgstr "Dispositivo de captura:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 #, fuzzy msgid "Ring device:" msgstr "Dispositivo de sonido:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 #, fuzzy msgid "Playback device:" msgstr "Dispositivo de reproducción:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Activar cancelación de eco" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 #, fuzzy msgid "Audio" msgstr "Audio" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 #, fuzzy msgid "Video input device:" msgstr "Dispositivo de entrada de vídeo:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Resolución de vídeo preferida:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Dispositivo de entrada de vídeo:" + +#: ../gtk/parameters.ui.h:48 #, fuzzy msgid "Video" msgstr "Vídeo " -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Configuración multimedia" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "Esta sección define su dirección SIP cuando no utiliza una cuenta SIP" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Su nombre a mostrar (x ej: Pepito Pérez):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 #, fuzzy msgid "Your username:" msgstr "Su nombre de usuario:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 #, fuzzy msgid "Your resulting SIP address:" msgstr "Su dirección SIP resultante:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 #, fuzzy msgid "Default identity" msgstr "Identidad predeterminada" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Añadir" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Editar" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Eliminar" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 #, fuzzy msgid "Proxy accounts" msgstr "Cuentas Proxy" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Borrar todas las contraseñas" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 #, fuzzy msgid "Privacy" msgstr "Privacidad" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "Gestionar cuentas SIP" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Activar" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Desactivar" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 #, fuzzy msgid "Codecs" msgstr "Códecs" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 significa \"ilimitado\"" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Velocidad límite de subida en Kbit/seg" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Velocidad límite de descarga en Kbit/seg:" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "Activar control de frecuencia adaptativo" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1372,35 +1447,58 @@ msgstr "" "Control de frecuencia adaptativo es una técnica que estima dinámicamente " "el ancho de banda disponible durante la llamada." -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Control de ancho de banda" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 #, fuzzy msgid "Codecs" msgstr "Códecs" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 #, fuzzy msgid "Language" msgstr "Idioma" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Mostrar opciones avanzadas" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 #, fuzzy msgid "Level" msgstr "Nivel" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 #, fuzzy msgid "User interface" msgstr "Interfaz de Usuario" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Dirección del Servidor:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Error de autenticación" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "etiqueta" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Cuentas Proxy" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 #, fuzzy msgid "Done" msgstr "Hecho" @@ -1430,7 +1528,7 @@ msgstr "Espere por favor" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Configuración" #: ../gtk/dscp_settings.ui.h:2 @@ -1487,6 +1585,15 @@ msgid "Round trip time" msgstr "Propiedades de sonido" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Resolución de vídeo preferida:" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Información de contacto" @@ -1572,19 +1679,141 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Configuración" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "no disponible" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Códecs" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Audio" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "Dirección SIP" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Buscar a alguien" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Vídeo " + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Conectando..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "abortada" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "completada" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "perdida" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1599,109 +1828,82 @@ msgstr "" "Estado: %s\n" "Duración: %i min %i seg\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Llamada saliente" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 #, fuzzy msgid "Ready" msgstr "Preparado" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Confirmación" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Buscando el número de teléfono del destinatario…" -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "No se ha podido resolver este número." -#: ../coreapi/linphonecore.c:2252 -#, fuzzy -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Dirección SIP mal escrita. Una dirección SIP es del tipo " - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 #, fuzzy msgid "Contacting" msgstr "Contactando" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 #, fuzzy msgid "Could not call" msgstr "No se pudo llamar" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 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:2752 +#: ../coreapi/linphonecore.c:2952 #, fuzzy msgid "is contacting you" msgstr "le está llamando" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "y ha solicitado auto respuesta." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "Modificando parámetros de llamada…" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Conectado." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 #, fuzzy msgid "Call aborted" msgstr "Llamada abortada" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "No se pudo pausar la llamada" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "Pausando la llamada actual..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Tu ordenador parece estar usando los controladores de sonido de ALSA.\n" -"Ésta es la mejor elección. Sin embargo, el módulo de emulación pcm de OSS\n" -"no se encuentra y linphone lo necesita. Por favor ejecute\n" -"'modprobe snd-pcm-oss' como root para cargarlo." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Tu ordenador parece estar usando los controladores de sonido de ALSA.\n" -"Ésta es la mejor elección. Sin embargo, el módulo de emulación mixer de OSS\n" -"no se encuentra y linphone lo necesita. Por favor ejecute\n" -" 'modprobe snd-mixer-oss' como root para cargarlo." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "Búsqueda STUN en proceso…" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1754,10 +1956,15 @@ msgid "Pending" msgstr "Pendiente" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Duración" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Bug-desconocido" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1765,7 +1972,7 @@ msgstr "" "La dirección del Proxy SIP que ha introducido no es válida, debe empezar con " "\"sip:\" seguido del hostname." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1774,139 +1981,172 @@ msgstr "" "Debe ser del tipo sip:username@proxydomain, como por ejemplo sip:" "alice@example.net" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, fuzzy, c-format msgid "Could not login as %s" msgstr "No se pudo iniciar sesión como %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 #, fuzzy msgid "Remote ringing." msgstr "El destinatario está sonando..." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 #, fuzzy msgid "Remote ringing..." msgstr "El destinatario está sonando..." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "Medios iniciales." -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "La llamada con %s está puesta en pausa." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "Llamada respondida por %s - en espera." -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 #, fuzzy msgid "Call resumed." msgstr "Llamada reanudada." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, fuzzy, c-format msgid "Call answered by %s." msgstr "Llamada respondida por %s." -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 #, fuzzy msgid "We have been resumed." msgstr "Nos han reanudado..." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 #, fuzzy msgid "Call is updated by remote." msgstr "La llamada ha sido actualizada por el destinatario..." -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 #, fuzzy msgid "Call terminated." msgstr "Llamada finalizada." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "El usuario está ocupado." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "El usuario no está disponible temporalmente." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "El usuario no quiere que le molesten." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Llamada rechazada." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "No hay respuesta." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "Error de protocolo." -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "Redigirida" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 #, fuzzy msgid "Call failed." msgstr "La llamada ha fallado." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Se ha registrado con éxito en %s." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Cancelación de registro en %s completada." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "timeout sin respuesta" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "El registro en %s ha fallado." -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "El tóken de autenticación es%s" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, 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" +#, fuzzy +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "Dirección SIP mal escrita. Una dirección SIP es del tipo " + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Tu ordenador parece estar usando los controladores de sonido de ALSA.\n" +#~ "Ésta es la mejor elección. Sin embargo, el módulo de emulación pcm de " +#~ "OSS\n" +#~ "no se encuentra y linphone lo necesita. Por favor ejecute\n" +#~ "'modprobe snd-pcm-oss' como root para cargarlo." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Tu ordenador parece estar usando los controladores de sonido de ALSA.\n" +#~ "Ésta es la mejor elección. Sin embargo, el módulo de emulación mixer de " +#~ "OSS\n" +#~ "no se encuentra y linphone lo necesita. Por favor ejecute\n" +#~ " 'modprobe snd-mixer-oss' como root para cargarlo." #~ msgid "Chat with %s" #~ msgstr "Conversación con %s" @@ -1940,10 +2180,6 @@ msgstr[1] "Tiene %i llamadas perdidas." #~ msgid "Verifying" #~ msgstr "Verificando" -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Confirmación" - #~ msgid "Creating your account" #~ msgstr "Creando su cuenta" @@ -1979,10 +2215,6 @@ msgstr[1] "Tiene %i llamadas perdidas." #~ msgid "No common codecs" #~ msgstr "No hay códecs comunes" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Error de autenticación" - #, fuzzy #~ msgid "Contact list" #~ msgstr "Lista de contactos " @@ -2054,10 +2286,6 @@ msgstr[1] "Tiene %i llamadas perdidas." #~ msgid "Gone" #~ msgstr "Ausente" -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Dirección SIP" - #, fuzzy #~ msgid "Display filters" #~ msgstr "Filtros a mostrar" @@ -2170,9 +2398,6 @@ msgstr[1] "Tiene %i llamadas perdidas." #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "Se recomienda encarecidamente usar el puerto 5060." -#~ msgid "SIP port" -#~ msgstr "Puerto SIP" - #~ msgid "@" #~ msgstr "@" @@ -2239,10 +2464,6 @@ msgstr[1] "Tiene %i llamadas perdidas." #~ msgid "Index" #~ msgstr "Índice" -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Dirección del Servidor:" - #~ msgid "28k modem" #~ msgstr "módem 28k" diff --git a/po/fr.po b/po/fr.po index 02c1f8fca..9f45b8dbc 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2013-04-09 13:57+0100\n" "Last-Translator: Simon Morlat \n" "Language-Team: french \n" @@ -15,12 +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:969 #, c-format msgid "Call %s" msgstr "Appeler %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Chatter avec %s" @@ -57,8 +57,8 @@ msgstr[1] "" #, c-format msgid "%i second" msgid_plural "%i seconds" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%i seconde" +msgstr[1] "%i secondes" #: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 #, c-format @@ -94,35 +94,35 @@ msgstr "Moi" msgid "Couldn't find pixmap file: %s" msgstr "Icone non trouvée: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "Contact sip invalide !" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "affiche des informations de debogage" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "chemin vers le fichier de logs." -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "Démarrer linphone avec la vidéo désactivée." -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "Démarre iconifié, sans interface principale." -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "adresse à appeler maintenant" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "si positionné, répond automatiquement aux appels entrants" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -130,12 +130,16 @@ 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 +#: ../gtk/main.c:151 +msgid "Configuration file" +msgstr "Ficher de configuration" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Appel avec %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -149,68 +153,67 @@ msgstr "" "Si vous répondez non, cette personne sera mise temporairement sur liste " "noire." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Entrez le mot de passe pour %s\n" " sur le domaine %s:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 msgid "Call error" msgstr "Erreur lors de l'appel" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Appel terminé." -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Répondre" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Refuser" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 msgid "Call paused" msgstr "Appel en pause" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, c-format msgid "by %s" msgstr "b>par %s" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s propose de démarrer la vidéo. Acceptez-vous ?" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Lien site web" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - un téléphone video pour l'internet" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (par défaut)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "Transfert vers %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -218,171 +221,171 @@ 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "Un visiophone libre" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "Ajouter au carnet d'adresse" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Info de présence" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nom" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 msgid "Call" msgstr "Appeler" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Rechercher dans l'annuaire de %s" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Editer le contact '%s'" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Supprimer le contact '%s'" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, c-format msgid "Delete chat history of '%s'" msgstr "Supprimer l'historique de chat de '%s'" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Ajouter un contact depuis l'annuaire %s" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Fréquence (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Etat" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" -msgstr "Débit min. (kbit/s)" +#: ../gtk/propertybox.c:574 +msgid "Bitrate (kbit/s)" +msgstr "Débit (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Paramètres" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Activé" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Désactivé" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Compte" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "Anglais" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Suédois" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Italien" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Espagnol" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "Portugais brésilien" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Polonais" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Allemand" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Russe" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Néérlandais" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Hongrois" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Tchèque" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "简体中文" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "Chinois traditionnel" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "Norvégien" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "Hébreu" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "Serbe" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 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 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "Aucun" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -447,59 +450,63 @@ msgstr "J'ai déjà un compte linphone.org et je souhaite l'utiliser" msgid "I have already a sip account and I just want to use it" msgstr "J'ai déjà un compte Sip et je souhaite l'utiliser" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "Je veux spécifier une URI de configuration" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "Entrez votre identifiant linphone.org" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Nom d'utilisateur:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Mot de passe:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "Entrez les informations concernant votre compte" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 msgid "Username*" msgstr "Nom d'utilisateur*" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 msgid "Password*" msgstr "Mot de passe*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "Domaine*" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "(*) Champs requis" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 msgid "Username: (*)" msgstr "Nom d'utilisateur: (*)" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 msgid "Password: (*)" msgstr "Mot de passe: (*)" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "Confirmez votre mot de passe: (*)" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." @@ -508,11 +515,11 @@ msgstr "" "serveur n'est pas accessible.\n" "Merci d'essayer à nouveau." -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Merci. Votre compte est maintenant configuré et prêt à être utilisé." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" @@ -522,35 +529,40 @@ msgstr "" "par email.\n" "Puis appuyez sur suivant." -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Assistant de configuration de compte." + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Bienvenue dans l'assistant de configuration de compte." -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Assistant de configuration de compte." -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "Configurez votre compte (étape 1/1)" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "Entrez votre identifiant sip (étape 1/1)" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "Entrez les informations concernant votre compte (étape 1/2)" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "Validation (étape 2/2)" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "Erreur" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "En cours d’arrêt." @@ -565,18 +577,16 @@ 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 -#, fuzzy msgid "Not used" -msgstr "Non trouvé" +msgstr "Non utilisé" #: ../gtk/incall_view.c:220 msgid "ICE not activated" msgstr "ICE non activé" #: ../gtk/incall_view.c:222 -#, fuzzy msgid "ICE failed" -msgstr "L'appel a échoué." +msgstr "Erreur ICE" #: ../gtk/incall_view.c:224 msgid "ICE in progress" @@ -587,9 +597,8 @@ msgid "Going through one or more NATs" msgstr "Via un ou plusieurs NATs" #: ../gtk/incall_view.c:228 -#, fuzzy msgid "Direct" -msgstr "Redirection" +msgstr "En direct" #: ../gtk/incall_view.c:230 msgid "Through a relay server" @@ -619,133 +628,147 @@ msgstr "uPnP a échoué." 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:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Raccrocher" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "Tentative d'appel..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "bon" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "moyen" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "faible" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "très faible" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "nulle" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "indisponible" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "Sécurisé par SRTP" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Sécurisé par ZRTP- [jeton: %s]" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "Marquer comme non vérifié" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Marquer comme vérifié" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "En conférence" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "Appel en cours" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "Appel en attente" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Appel terminé." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "Transfert en cours" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "Transfert terminé" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 msgid "Transfer failed." msgstr "Transfert échoué" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "Reprendre" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 -#, fuzzy +#: ../gtk/incall_view.c:915 msgid "(Paused)" -msgstr "Pause" +msgstr "(en attente)" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Entrez vos identifiants pour %s" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "chargement depuis %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "Le chargement de la configuration depuis %s a échoué." + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Nom du correspondant" @@ -791,89 +814,89 @@ msgid "_Options" msgstr "" #: ../gtk/main.ui.h:18 +msgid "Set configuration URI" +msgstr "URI de configuration" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "Toujours démarrer la vidéo" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Se voir" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "_Aide" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "Fenêtre de débogage" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "_Site web" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "Assistant de compte" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "Adresse SIP ou numéro" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "Démarrer un nouvel appel" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "Contacts" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Ajouter" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Editer" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Rechercher" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "Ajouter un contact depuis l'annuaire" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "Ajouter un contact." -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Recent calls" msgstr "Appels récents" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Mon identité sip:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../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:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Mot de passe" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Connexion internet:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Me connecter automatiquement" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Information de login" @@ -931,6 +954,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -965,10 +989,6 @@ msgstr "Linphone - Authentification demandée" msgid "Please enter the domain password" msgstr "Entrez votre mot de passe pour le domaine" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Historique des appels" @@ -1006,273 +1026,313 @@ msgid "Looks like sip:" msgstr "De la forme sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (optionnel):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Période d'enregistrement (secondes):" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "Paramètres de contact (optionnel):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Route (optionnel):" + +#: ../gtk/sip_account.ui.h:10 +msgid "Transport" +msgstr "Transport" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "S'enregistrer" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Publier la présence" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "Configurer un compte SIP" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "Carte son par défaut" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "une carte son" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "camera par défaut" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Codecs audio" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Codecs vidéo" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Réglages" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Spécifier la Maximum Transmission Unit" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "Envoyer les digits en tant que SIP INFO" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "Utiliser l'IPv6 au lieu d'IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Transport" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "Type d'encryption media" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "Champs DSCP" - -#: ../gtk/parameters.ui.h:20 -msgid "Fixed" -msgstr "" - -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - #: ../gtk/parameters.ui.h:22 +msgid "Fixed" +msgstr "Fixe" + +#: ../gtk/parameters.ui.h:23 #, fuzzy msgid "Media encryption is mandatory" msgstr "Type d'encryption media" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "Champs DSCP" + +#: ../gtk/parameters.ui.h:26 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:27 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "Protocoles réseaux et ports" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Connexion directe à l'Internet" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "Derrière un pare-feu (spécifier la passerelle ci dessous)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Adresse IP publique:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Derrière un pare-feu (utiliser STUN)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 msgid "Behind NAT / Firewall (use ICE)" msgstr "Derrière un pare-feu (utiliser ICE)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 msgid "Behind NAT / Firewall (use uPnP)" msgstr "Derrière un pare-feu (utiliser uPnP)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Adresse IP publique:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "Serveur STUN:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "Paramètres liés au pare-feu" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Paramètres réseau" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Sonnerie:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Périphérique de capture:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Périphérique de sonnerie:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Périphérique d'écoute:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Activer l'annulation d'écho" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Son" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Périphérique d'entrée vidéo" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Résolution de vidéo préférée:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +msgid "Video output method:" +msgstr "Type de rendu video:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Video" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Paramètres multimedia" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" "Cette rubrique permet de définir son adresse SIP lorsqu'on ne possède pas de " "compte SIP" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Votre nom d'affichage (ex: John Doe)" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Votre nom d'utilisateur:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Votre adresse SIP:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Identité par défaut" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" -msgstr "" +msgstr "Assistant" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Ajouter" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Editer" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Enlever" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Comptes SIP via des proxy" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Effacer tous les mots de passe" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Sécurité" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 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:63 ../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:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Désactiver" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "Indiquez 0 pour ne pas mettre de limite" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Limite de débit montant en kbits/sec:" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Limite de débit descendant en kbits/sec:" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "Activer le control de débit adaptatif." -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1281,31 +1341,51 @@ msgstr "" "de l'audio et de la video en fonction de la bande passante disponible, " "durant l'appel." -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Gestion de la bande passante" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Langue" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Montrer les réglages avancés" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "Niveau" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Interface utilisateur" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +msgid "Server address:" +msgstr "Adresse du serveur:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +msgid "Authentication method:" +msgstr "Méthode d'authentification:" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "" + +#: ../gtk/parameters.ui.h:81 +msgid "LDAP Account setup" +msgstr "Configuration LDAP" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Fermer" @@ -1330,8 +1410,8 @@ msgid "Please wait" msgstr "En attente" #: ../gtk/dscp_settings.ui.h:1 -msgid "Dscp settings" -msgstr "Réglages Dscp" +msgid "DSCP settings" +msgstr "Réglages DSCP" #: ../gtk/dscp_settings.ui.h:2 msgid "SIP" @@ -1347,7 +1427,7 @@ msgstr "" #: ../gtk/dscp_settings.ui.h:5 msgid "Set DSCP values (in hexadecimal)" -msgstr "" +msgstr "Indiquez les valeurs DSCP (en hexacdécimal)" #: ../gtk/call_statistics.ui.h:1 msgid "Call statistics" @@ -1363,7 +1443,7 @@ msgstr "Codecs vidéo" #: ../gtk/call_statistics.ui.h:4 msgid "Audio IP bandwidth usage" -msgstr "" +msgstr "Bande passante audio" #: ../gtk/call_statistics.ui.h:5 #, fuzzy @@ -1372,7 +1452,7 @@ msgstr "Type d'encryption media" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" -msgstr "" +msgstr "Bande passante video" #: ../gtk/call_statistics.ui.h:7 #, fuzzy @@ -1381,16 +1461,23 @@ msgstr "Type d'encryption media" #: ../gtk/call_statistics.ui.h:8 msgid "Round trip time" -msgstr "" +msgstr "Temps d'aller retour" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "Taille de video reçue" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "Taille de video envoyée" + +#: ../gtk/call_statistics.ui.h:11 msgid "Call statistics and information" msgstr "Statistiques de l'appel et informations" #: ../gtk/tunnel_config.ui.h:1 -#, fuzzy msgid "Configure VoIP tunnel" -msgstr "Configuer un compte SIP" +msgstr "Configuer le mode tunnel" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" @@ -1468,19 +1555,141 @@ msgstr "" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Réglages" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "uPnP est indisponible" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Codecs" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Son" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "Adresse SIP ou numéro" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Rechercher une personne" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Video" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "Cette boite de dialogue vous permet de spécifier une address http ou https où la configuration doit être téléchargée au démarrage\n" +"Entry l'URI ci dessous. Après avoir validé, Linphone va redémarrer automatiquement pour charger et prendre en compte la nouvelle configuration." + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +msgid "Configuring..." +msgstr "Configuration en cours" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "Veuillez patenter un instant pendant le chargement de la configuration distante..." + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "abandonné" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "terminé" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "manqué" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1495,103 +1704,76 @@ msgstr "" "Etat: %s\n" "Durée: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Appel sortant" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Prêt." -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +msgid "Configuring" +msgstr "Configuration en cours" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Recherche de la destination du numéro de téléphone..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "La destination n'a pu être trouvée." -#: ../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:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Appel de" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "Echec de l'appel" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 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:2752 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "vous appelle" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "et sollicite un décrochage automatique." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "Modifications des paramètres d'appels..." -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "En ligne." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "Appel abandonné" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "La mise en attente a échoué" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "Mise en attente de l'appel..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Votre ordinateur semble utiliser les pilotes sons ALSA.\n" -"C'est en g��al le meilleur choix, cependant un module\n" -"d'emulation oss est manquant et linphone en a besoin.\n" -"Veuillez s'il vous plait executer la commande\n" -"'modprobe snd-pcm-oss' en tant que root afin de le charger." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Votre ordinateur semble utiliser les pilotes sons ALSA. C'est en g��al le\n" -"meilleur choix, cependant un module d'emulation est manquant et linphone en\n" -"a besoin. Veuillez s'il vous plait executer la commande\n" -"'modprobe snd-mixer-oss' en tant que root afin de le charger." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "Découverte STUN en cours" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1640,10 +1822,14 @@ msgid "Pending" msgstr "En attente" #: ../coreapi/friend.c:66 +msgid "Vacation" +msgstr "En congé" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Bug inconnu" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1651,7 +1837,7 @@ msgstr "" "L'adresse SIP du proxy est invalide. Elle doit commencer par \"sip:\" suivie " "par un nom de domaine." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1660,132 +1846,166 @@ msgstr "" "Elle doit être de la forme sip:username@domain, comme par example sip:" "alice@example.net" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "Echec de la connexion en tant que %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "Sonnerie distante." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "Sonnerie distante..." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "Prise d'appel anticipée." -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "%s est maintenant en attente." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "Appel répondu par %s - en attente" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "Appel repris." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "Appel répondu par %s." -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 -#, fuzzy +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." -msgstr "Reprise..." +msgstr "Appel repris." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." -msgstr "" +msgstr "L'appel a été mis en attente." -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 #, fuzzy msgid "Call is updated by remote." msgstr "L'appel a été repris par le correspondant." -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Appel terminé." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Occupé..." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "L'usager est temporairement indisponible." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "L'usager ne souhaite pas être dérangé" -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Appel décliné." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "Pas de réponse." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "Erreur de protocole" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "Redirection" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." -msgstr "" +msgstr "Paramètres media incompatibles." -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "L'appel a échoué." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Enregistrement sur %s effectué." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "Désenregistrement sur %s effectué." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "Pas de réponse" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "Echec de l'enregistrement sur %s: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, c-format msgid "Authentication token is %s" msgstr "Le jeton d'authentification est %s" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Vous avez manqué %i appel" msgstr[1] "Vous avez manqué %i appels" +#~ msgid "" +#~ "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 "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Votre ordinateur semble utiliser les pilotes sons ALSA.\n" +#~ "C'est en g��al le meilleur choix, cependant un module\n" +#~ "d'emulation oss est manquant et linphone en a besoin.\n" +#~ "Veuillez s'il vous plait executer la commande\n" +#~ "'modprobe snd-pcm-oss' en tant que root afin de le charger." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Votre ordinateur semble utiliser les pilotes sons ALSA. C'est en g��al " +#~ "le\n" +#~ "meilleur choix, cependant un module d'emulation est manquant et linphone " +#~ "en\n" +#~ "a besoin. Veuillez s'il vous plait executer la commande\n" +#~ "'modprobe snd-mixer-oss' en tant que root afin de le charger." + #~ msgid "Keypad" #~ msgstr "Clavier" @@ -1795,10 +2015,6 @@ msgstr[1] "Vous avez manqué %i appels" #~ msgid "Choosing a username" #~ msgstr "Choix du nom d'utilisateur" -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Information sur le contact" - #~ msgid "Enable video" #~ msgstr "Activer la video" @@ -1818,9 +2034,6 @@ msgstr[1] "Vous avez manqué %i appels" #~ msgid "No common codecs" #~ msgstr "Pas de codecs commun" -#~ msgid "Authentication failure" -#~ msgstr "Echec d'authentification" - #~ msgid "" #~ "Pause all calls\n" #~ "and answer" diff --git a/po/he.po b/po/he.po index 32e51337c..bcbfa9161 100644 --- a/po/he.po +++ b/po/he.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 3.5.99.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-04-08 16:59+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2013-04-24 21:31+0200\n" "Last-Translator: Isratine Citizen \n" "Language-Team: Rahut Project \n" @@ -20,12 +20,12 @@ msgstr "" "X-Generator: Poedit 1.5.4\n" # צור קשר עם -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "התקשר אל %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "שלח טקסט אל %s" @@ -100,48 +100,48 @@ msgid "Couldn't find pixmap file: %s" msgstr "לא ניתן למצוא קובץ ‫pixmap: ‫%s" # איש־קשר -#: ../gtk/chat.c:324 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "כתובת sip לא תקפה !" # cli -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 #, fuzzy msgid "log to stdout some debug information while running." msgstr "רשום אל stdout מידע ניפוי שגיאות מסוים בזמן ביצוע." # cli -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 #, fuzzy msgid "path to a file to write logs into." msgstr "נתיב אל קובץ שברצונך לרשום אליו את הרשומות." # cli -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 #, fuzzy msgid "Start linphone with video disabled." msgstr "התחל את לינפון עם וידאו מנוטרל." # cli -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 #, fuzzy msgid "Start only in the system tray, do not show the main interface." msgstr "התחל במגש המערכת בלבד, אל תציג את הממשק הראשי." # cli -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 #, fuzzy msgid "address to call right now" msgstr "כתובת להתקשרות ברגע זה" # cli -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 #, fuzzy msgid "if set automatically answer incoming calls" msgstr "באם אפשרות זו נקבעת ענה אוטומטית לקריאות נכנסות" # cli -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 #, fuzzy msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" @@ -150,14 +150,20 @@ msgstr "" "ציין מדור העבודה (אמור להיות מבוסס על ההתקנה, למשל: c:\\Program Files" "\\Linphone)" -#: ../gtk/main.c:515 +# וידוא +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "אימות" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "התקשרות באמצעות %s" # הקשר שלהם # אם התשובה -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -170,75 +176,75 @@ msgstr "" "שלך ?\n" "היה ותשובתך תהיה לא, אדם זה יהיה מסומן באופן זמני ברשימה השחורה." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "נא להזין את סיסמתך עבור שם משתמש %s\n" " בתחום %s:" # שיחה -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 msgid "Call error" msgstr "שגיאת קריאה" # Conversation ended -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3189 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "שיחה הסתיימה" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:239 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "לענות" # דחיה -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "לדחות" # Conversation paused -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 msgid "Call paused" msgstr "שיחה הושהתה" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, c-format msgid "by %s" msgstr "על ידי %s" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "‏%s רוצה להתחיל וידאו. האם אתה מסכים ?" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "קישור אתר רשת" # ‫Linphone - וידאופון במרשתת -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "‫Linphone - וידאופון אינטרנטי" # משתמטת -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "‫%s (ברירת מחדל)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "אנחנו מועברים אל %s" # קריאות שמע -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -246,177 +252,178 @@ msgstr "" "לא אותרו כרטיסי קול במחשב זה.\n" "לא תהיה ביכולתך לשלוח או לקבל שיחות אודיו." -#: ../gtk/main.c:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "וידאופון SIP חופשי" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "הוסף אל ספר כתובות" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "מצב נוכחות" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "שם" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 msgid "Call" msgstr "קריאה" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "שיחה" # a name or a number -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "חיפוש במדור %s" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "ערוך איש קשר '%s'" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "מחק איש קשר '%s'" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, c-format msgid "Delete chat history of '%s'" msgstr "מחק היסטוריית שיחה של '%s'" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "הוסף איש קשר חדש מן מדור %s" # קצב תדר תדירות מהירות -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "שיעור (הרץ)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "מצב" # שיעור סיביות מינימלי -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "קצב נתונים מינימלי (קי״ב/שנ׳)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "פרמטרים" # מאופשר -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "מופעל" # מנוטרל -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "לא מופעל" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "חשבון" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "English" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Svenska" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Italiano" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Español" # português do Brasil -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "português brasileiro" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Polski" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Deutsch" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Русский" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Nederlands" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Magyar" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Česky" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "中文" # 繁体字 -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "繁體字" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "norsk" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "עברית" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "српски srpski" # selected הנבחרת -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "עליך לאתחל את לינפון כדי שהשפה החדשה תיכנס לתוקף." -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "ללא" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -482,62 +489,66 @@ msgstr "כבר קיים חשבון linphone.org ברשותי וברצוני לע msgid "I have already a sip account and I just want to use it" msgstr "כבר קיים חשבון sip ברשותי וברצוני לעשות בו שימוש" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "הזן את שם משתמשך אצל linphone.org" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "שם משתמש:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "סיסמה:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "הזן את מידע חשבונך" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 msgid "Username*" msgstr "שם משתמש*" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 msgid "Password*" msgstr "סיסמה*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "מתחם*" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "פרוקסי" # נדרשים -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "(*) שדות חובה" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 msgid "Username: (*)" msgstr "שם משתמש: (*)" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 msgid "Password: (*)" msgstr "סיסמה: (*)" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "דוא״ל: (*)" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "אימות סיסמתך: (*)" # אינו בר־השגה # לשוב אחורה -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." @@ -545,12 +556,12 @@ msgstr "" "שגיאה, חשבון לא אומת, שם משתמש כבר בשימוש או שרת לא ניתן להשגה.\n" "נא לחזור ולנסות שוב." -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "תודה לך. חשבונך מוגדר ומוכן לשימוש כעת." # לאחר מכן -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" @@ -559,39 +570,44 @@ msgstr "" "נא לאמת את חשבונך באמצעות הקלקה על הקישור ששלחנו לך עתה באמצעות דוא״ל.\n" "אחרי כן נא לחזור לכאן וללחוץ על הלחצן 'קדימה'." +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "אשף הגדרת חשבון" + # Wizard אשף # סייע -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "ברוך בואך אל אשף הגדרת החשבון" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "אשף הגדרת חשבון" # שלב -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "הגדרת חשבונך (צעד 1/1)" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "הזנת שם משתמש sip (צעד 1/1)" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "הזנת מידע חשבון (צעד 1/2)" # תקפות -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "אימות (צעד 2/2)" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "שגיאה" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "מסיים כעת" @@ -657,7 +673,7 @@ msgstr "‏uPnP נכשלה" msgid "Direct or through server" msgstr "ישיר או דרך שרת" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" @@ -666,117 +682,122 @@ msgstr "" "הורדה: %f\n" "העלאה: %f (קי״ב/שנ׳)" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "%.3f שניות" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "נתק" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "מתקשר כעת..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "‭00::00::00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "טובה" # רגילה -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "ממוצעת" # weak חלשה חלושה רפויה רופפת -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "דלה" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "דלה מאוד" # רעה -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "גרועה מדי" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "לא זמינה" # באמצעות -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "מאובטחת על ידי SRTP" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "מאובטחת על ידי ZRTP - [אות אימות: %s]" # set or unset verification state of ZRTP SAS. -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "הגדר כלא מאומתת" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "הגדר כמאומתת" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "בשיחת ועידה" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "בשיחה כעת" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "שיחה מושהית" # שעות %02i דקות %02i שניות %02i # Force LTR time format (hours::minutes::seconds) with LRO chatacter (U+202D) -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "‭%02i::%02i::%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "שיחה הסתיימה." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "העברה מצויה כעת בעיצומה" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "העברה הסתיימה." -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 msgid "Transfer failed." msgstr "העברה נכשלה." -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "חזור" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "השהה" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" @@ -785,15 +806,25 @@ msgstr "" "מקליט אל תוך\n" "%s %s" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "(מושהה)" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "נא להזין מידע התחברות עבור %s" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + # מתקשר Caller # זה ש: נתקשר או מתוקשר או הותקשר? #: ../gtk/main.ui.h:1 @@ -841,93 +872,95 @@ msgstr "אומדן איכות שיחה" msgid "_Options" msgstr "_אפשרויות" +# וידוא #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "אימות" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "התחל תמיד וידאו" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "אפשר ראות-עצמית" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "_עזרה" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "הצג חלון ניפוי שגיאות" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "_עמוד הבית" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "בדיקת _עדכונים" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "אשף חשבון" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "כתובת SIP או מספר טלפון" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "התחל שיחה חדשה" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "אנשי קשר" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "הוסף" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "ערוך" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "חיפוש" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "הוסף אנשי קשר מן מדור" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "הוסף איש קשר" # קריאות אחרונות -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Recent calls" msgstr "שיחות אחרונות" # הזהות הנוכחית שלי -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "זהותי הנוכחית:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "שם משתמש" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "סיסמה" # מרשתת -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "חיבור אינטרנט:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "חבר אותי אוטומטית" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "מזהה משתמש" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "מידע התחברות" @@ -988,6 +1021,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -1023,10 +1057,6 @@ msgstr "‫Linphone - נדרש אימות" msgid "Please enter the domain password" msgstr "נא להזין את סיסמת המתחם" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "מזהה משתמש" - # קריאות #: ../gtk/call_logs.ui.h:1 msgid "Call history" @@ -1066,286 +1096,331 @@ msgid "Looks like sip:" msgstr "נראה כמו ‪sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "ניתוב (רשות):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "משך רישום (בשניות):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "ניתוב (רשות):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "ניתוב (רשות):" + +# מוביל +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "טרנספורט" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "רישום" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "פרסם מידע נוכחות" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "הגדרת חשבון ‫SIP" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "כרטיס קול משתמט" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "כרטיס קול" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "מצלמה משתמטת" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "קודקים של אודיו" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "קודקים של וידאו" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "‏SIP ‏(UDP)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "‏SIP ‏(TCP)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "‏SIP ‏(TLS)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "הגדרות" # שידור -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "הגדר יחידת תמסורת מרבית:" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "שלח טזמ״תים (DTMFs) כמידע SIP" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "השתמש בפרוטוקול IPv6 במקום בפרוטוקול IPv4" # מוביל -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "טרנספורט" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "סוג הצפנת מדיה" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "וידאו RTP/UDP:" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "אודיו RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "שדות DSCP" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "מקובע" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "מינהור" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "הצפנת מדיה הינה מנדטורית" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "מינהור" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "שדות DSCP" + +#: ../gtk/parameters.ui.h:26 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:27 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "פרוטוקולי רשת תקשורת ופורטים" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "חיבור ישיר אל האינטרנט" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify 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 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "מאחורי NAT / חומת אש (בעזרת STUN לפתירה)" # שימוש ב־STUN # utilize -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 msgid "Behind NAT / Firewall (use ICE)" msgstr "מאחורי NAT / חומת אש (בעזרת ICE)" # שימוש ב־STUN # utilize -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 msgid "Behind NAT / Firewall (use uPnP)" msgstr "מאחורי NAT / חומת אש (בעזרת uPnP)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "כתובת IP פומבית:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "שרת STUN:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "‫NAT וחומת אש" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "הגדרות רשת תקשורת" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "צליל צלצול:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "התקן ALSA מיוחד (רשות):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "התקן לכידה:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "התקן צלצול:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "התקן פס קול:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "אפשר ביטול הד" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "אודיו" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "התקן קלט וידאו:" # רצויה -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "רזולוציית וידאו מועדפת:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "התקן קלט וידאו:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "וידאו" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "הגדרות מולטימדיה" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "חלק זה מגדיר את כתובת ה־SIP כאשר אינך עושה שימוש בחשבון SIP" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "שם התצוגה שלך (למשל: יורם יהודה):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "שם המשתמש שלך:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "כתובת SIP נובעת:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "זהות משתמטת" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "אשף" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "הוסף" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "ערוך" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "הסר" # חשבונות מתווכים -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "חשבונות Proxy" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "מחק סיסמאות" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "פרטיות" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "ניהול חשבונות ‫SIP" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "אפשר" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "נטרל" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "קודקים" # ללא הגבלה -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 מסמל \"בלי הגבלה\"" # does KiB mean kibibyte? -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "מגבלת מהירות העלאה בקי״ב/שנ׳:" # האם KiB זה kibibyte? # קי״ב (1024) אל מול ק״ב (1000) -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "מגבלת מהירות הורדה בקי״ב/שנ׳:" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "אפשר בקרת קצב מסתגלת" # שיטה ניחוש -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1355,31 +1430,55 @@ msgstr "" # פס רוחב # טווח תדרים -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "בקרת רוחב פס" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "קודקים" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "שפה" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "הצג הגדרות מתקדמות" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "רמה" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "ממשק משתמש" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "כתובת SIP Proxy:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "כשל באימות" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "תוויות" + +# חשבונות מתווכים +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "חשבונות Proxy" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "סיום" @@ -1405,7 +1504,8 @@ msgid "Please wait" msgstr "נא להמתין" #: ../gtk/dscp_settings.ui.h:1 -msgid "Dscp settings" +#, fuzzy +msgid "DSCP settings" msgstr "הגדרות Dscp" #: ../gtk/dscp_settings.ui.h:2 @@ -1457,6 +1557,16 @@ msgid "Round trip time" msgstr "זמן הלוך ושוב" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +# רצויה +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "רזולוציית וידאו מועדפת:" + +#: ../gtk/call_statistics.ui.h:11 msgid "Call statistics and information" msgstr "סטטיסטיקות ומידע שיחה" @@ -1540,20 +1650,143 @@ msgstr "2 [דהו]" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:227 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "הגדרות" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "‏uPnp לא זמינה" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "קודקים" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "אודיו" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "כתובת SIP או מספר טלפון" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +# חיפוש מאן דהו +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "חיפוש אחר מישהו" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "וידאו" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "מתחבר כעת..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "ננטשה" -#: ../coreapi/linphonecore.c:230 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "הסתיימה" -#: ../coreapi/linphonecore.c:233 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "הוחמצה" # needs to be tested -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1568,107 +1801,81 @@ msgstr "" "מצב: %s\n" "משך: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "קריאה יוצאת" -#: ../coreapi/linphonecore.c:1312 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "מוכן" -#: ../coreapi/linphonecore.c:2184 +# וידוא +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "אימות" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "מחפש כעת עבור יעד מספר טלפון..." -#: ../coreapi/linphonecore.c:2187 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "לא ניתן לפתור את מספר זה." -# לרוב -#: ../coreapi/linphonecore.c:2231 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"לא ניתן היה לפענח את הכתובת שניתנה. כתובת sip בדרך כלל נראית כך: sip:" -"user@domain" - -#: ../coreapi/linphonecore.c:2432 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "מתקשר כעת" -#: ../coreapi/linphonecore.c:2439 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "לא ניתן להתקשר" # מספר השיחות המקבילות המרבי -#: ../coreapi/linphonecore.c:2549 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "הגענו אל המספר המרבי של שיחות מקבילות, עמך הסליחה" -#: ../coreapi/linphonecore.c:2731 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "מתקשר/ת אליך" -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr " ומבקש/ת מענה אוטומטי." -#: ../coreapi/linphonecore.c:2732 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" # פרמטרי קריאה -#: ../coreapi/linphonecore.c:2799 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "מתאים כעת פרמטרים של שיחה..." -#: ../coreapi/linphonecore.c:3138 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "מקושר." -#: ../coreapi/linphonecore.c:3166 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "קריאה בוטלה" -#: ../coreapi/linphonecore.c:3357 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "לא ניתן להשהות את השיחה" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "משהה כעת שיחה נוכחית..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"נראה שמחשבך עושה שימוש במנהל התקן הקול ALSA.\n" -"זוהי הבחירה הטובה ביותר. אולם מודול ההדמיה (emulation module) של pcm oss\n" -"נעדר ולינפון זקוק לו. נא להריץ את הפקודה\n" -"‫'modprobe snd-pcm-oss' כמשתמש שורש (משתמש על) כדי להטעינו." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"נראה שמחשבך עושה שימוש במנהל התקן הקול ALSA.\n" -"זוהי הבחירה הטובה ביותר. אולם מודול ההדמיה (emulation module) של mixer oss\n" -"נעדר ולינפון זקוק לו. נא להריץ את הפקודה\n" -"‫'modprobe snd-mixer-oss' כמשתמש שורש (משתמש על) כדי להטעינו." - # במהלך (או) באמצע חיפוש... -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "בדיקת STUN מצויה כעת בעיצומה..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "צבירת מועמדים מקומיים של ICE מצויה כעת בעיצומה..." @@ -1722,10 +1929,15 @@ msgid "Pending" msgstr "בהמתנה" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "משך זמן" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "תקלה לא מוכרת" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1733,7 +1945,7 @@ msgstr "" "כתובת sip proxy שהזנת הינה שגויה, זו צריכה להתחיל עם‭\"sip:\" ‬ לאחר שם מארח." # כמו למשל -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1742,40 +1954,40 @@ msgstr "" "זו צריכה להיראות כמו sip:username@proxydomain, למשל sip:alice@example.net" # בשם כ־ -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "לא ניתן להתחבר בזהות %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "צלצול מרוחק." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "צלצול מרוחק..." # A SIP state -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "מדיה מוקדמת." -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "שיחה עם %s מושהית." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "קריאה נענתה על ידי %s - בהמתנה." # renewed -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "קריאה חודשה." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "קריאה נענתה על ידי %s." @@ -1783,104 +1995,136 @@ msgstr "קריאה נענתה על ידי %s." # לא תואם # אי תאימות # אי התאמה -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "חוסר תאימות, בדוק קודקים או הגדרות אבטחה..." -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "חזרנו." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "אנו מושהים על ידי צד אחר." # באופן מרוחק -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "שיחה עודכנה מרחוק." -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "קריאה הסתיימה." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "משתמש עסוק כעת." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "משתמש לא זמין זמנית." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "משתמש לא מעוניין שיפריעו לו." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "קריאה סורבה." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "אין תגובה." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "שגיאת פרוטוקול." -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "מכוון מחדש" # לא תואם # אי תאימות # אי התאמה -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "פרמטריי מדיה חסרי תואמים." -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "קריאה נכשלה." # הרשמה אצל %s הושלמה בהצלחה. -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "רישום אצל %s הושלם בהצלחה." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "אי רישום אצל %s סוים." # Pas de réponse # no response in defined time -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "אין היענות תוך זמן מוגדר" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "רישום אצל %s נכשל: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, c-format msgid "Authentication token is %s" msgstr "אות האימות הינה %s" # האם כדאי לחקות את הטלפונים הניידים? שיחות של נענו -#: ../coreapi/linphonecall.c:2319 +#: ../coreapi/linphonecall.c:2678 #, 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 "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "לא ניתן היה לפענח את הכתובת שניתנה. כתובת sip בדרך כלל נראית כך: sip:" +#~ "user@domain" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "נראה שמחשבך עושה שימוש במנהל התקן הקול ALSA.\n" +#~ "זוהי הבחירה הטובה ביותר. אולם מודול ההדמיה (emulation module) של pcm oss\n" +#~ "נעדר ולינפון זקוק לו. נא להריץ את הפקודה\n" +#~ "‫'modprobe snd-pcm-oss' כמשתמש שורש (משתמש על) כדי להטעינו." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "נראה שמחשבך עושה שימוש במנהל התקן הקול ALSA.\n" +#~ "זוהי הבחירה הטובה ביותר. אולם מודול ההדמיה (emulation module) של mixer " +#~ "oss\n" +#~ "נעדר ולינפון זקוק לו. נא להריץ את הפקודה\n" +#~ "‫'modprobe snd-mixer-oss' כמשתמש שורש (משתמש על) כדי להטעינו." #~ msgid "by %s" #~ msgstr "מאת %s" @@ -1923,9 +2167,6 @@ msgstr[1] "החמצת %i שיחות." #~ msgid "No common codecs" #~ msgstr "אין קודקים משותפים" -#~ msgid "Authentication failure" -#~ msgstr "כשל באימות" - #~ msgid "Please choose a username:" #~ msgstr "נא לבחור שם משתמש:" @@ -1953,10 +2194,6 @@ msgstr[1] "החמצת %i שיחות." #~ msgid "Verifying" #~ msgstr "מאמת כעת" -# וידוא -#~ msgid "Confirmation" -#~ msgstr "אימות" - #~ msgid "Creating your account" #~ msgstr "חשבונך נוצר כעת" diff --git a/po/hu.po b/po/hu.po index 65bbb3e7b..fb2e08033 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2013-03-26 19:00+0100\n" "Last-Translator: Viktor \n" "Language-Team: \n" @@ -17,12 +17,12 @@ msgstr "" "X-Generator: Poedit 1.5.4\n" "Plural-Forms: nplurals=1; plural=1 == 1 ? 0 : 1;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "%s hívása" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Szöveg küldése a következőnek: %s" @@ -98,35 +98,35 @@ msgstr "én" msgid "Couldn't find pixmap file: %s" msgstr "Nemtalálható a pixmap fájl: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "Érvénytelen sip partner !" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 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:99 +#: ../gtk/main.c:109 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:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "Linphone indítása, videó kikpacsolva. " -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 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:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "Cím azonnali híváshoz" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "Bekapcsolva automatikusan válaszol a bejövő hívásokra" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -134,12 +134,17 @@ 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:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Információk" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Hívás %s -el" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -152,68 +157,68 @@ msgstr "" "szeretné adni a partnerlistához?\n" "Ha nemmel válaszol, ez a személy átmenetileg tiltólistára kerül." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Kérem, adja meg jelszavát a következő felhasználónévhez: %s\n" "tartomány %s:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 msgid "Call error" msgstr "Hiba a hívás közben" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Hívás vége" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Hívás fogadása" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Elutasítás" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 msgid "Call paused" msgstr "Hívás várakoztatva" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, c-format msgid "by %s" msgstr "a következő által: %s" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s szerené elidítani a videót. Elfogadja?" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Internetes oldal" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - internetes videó telefon" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (Alapértelmezett)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "Át vagyunk irányítva ide: %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -221,171 +226,172 @@ 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "Egy ingyenes SIP video-telefon" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "Hozzáadás címjegyzékhez" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Jelenlét státusz" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Név" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 msgid "Call" msgstr "Hivás" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "Csevegés" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Keresés ebben a könyvtárban: %s" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Kapcsolatinformációk szerkesztése: '%s'" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "'%s' partner törlése" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "'%s' partner törlése" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Új partner hozzáadása ebből a könyvtárból: %s" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Érték (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Állapot" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Min bitrate (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Paraméterek" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Engedélyezve" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Tiltva" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Hozzáférés" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "angol" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "francia" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "svéd" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "olasz" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "spanyol" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "brazil-portugál" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "lengyel" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "német" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "orosz" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "japán" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "holland" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "magyar" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "cseh" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "egyszerúsített kínai" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "tradícionális kínai" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "norvég" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "héber" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 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:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "Nincs" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "ZRTP" @@ -448,59 +454,63 @@ msgstr "Már rendelkezem linphone.org fiókkal, azt szeretném használni" msgid "I have already a sip account and I just want to use it" msgstr "Már rendelkezem sip fiókkal, azt szeretném használni" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "Adja meg linphone.org felhasználónevét" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Felhasználónév:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Jelszó:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "Írja be fiókinformációit" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 msgid "Username*" msgstr "Felhasználónév*" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 msgid "Password*" msgstr "Jelszó*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "Tartomány" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "Proxy" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "(*) Mező kitöltése szükséges" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 msgid "Username: (*)" msgstr "Felhasználónév: (*)" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 msgid "Password: (*)" msgstr "Jelszó: (*)" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "E-mail: (*)" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "Jelszó megerősítése: (*)" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." @@ -509,11 +519,11 @@ msgstr "" "vagy a kiszolgáló nem elérhető.\n" "Kérjük, lépjen vissza és próbálja újra." -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Köszönjük! Az Ön fiókját beállítottuk és használatra kész." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" @@ -523,35 +533,40 @@ msgstr "" "hivatkozásra kattintva.\n" "Azután térjen vissza ide és kattintson a Következő gombra." -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Fiók beállítása varázsló" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "A fiók beállítása varázsló üdvözli Önt" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Fiók beállítása varázsló" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "Az Ön fiókjának beállítása (1/1 lépés)" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "Adja meg sip felhasználónevét (1/2 lépés)" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "Adja meg a fiókinformációt (1/2 lépés)" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "Érvényesítés (2/2 lépés)" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "Hiba" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "Befejezés" @@ -617,7 +632,7 @@ msgstr "uPnP nem sikerült" msgid "Direct or through server" msgstr "közvetlen vagy kiszolgálón keresztül" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" @@ -626,110 +641,115 @@ msgstr "" "letöltés: %f\n" "feltöltés: %f (kbit/mp)" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "%.3f másodperc" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Befejezés" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "Hívás folyamatban..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "jó" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "közepes" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "gyenge" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "nagyon gyenge" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "rossz" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "nem elérhető" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "SRTP-vel titkosítva" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "ZRTP-vel titkosítva - [hitelesítési jel: %s]" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "Beállítás ellenőrizetlenként" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Beállítás ellenőrzöttként" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "Konferencián" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "vonalban" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "Várakoztatott hívás" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Hívás vége." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "Átvitel folyamatban" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "Átvitel befejezve." -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 msgid "Transfer failed." msgstr "Az átvitel sikertelen." -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "Visszatérés" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Várakoztatás" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" @@ -738,15 +758,25 @@ msgstr "" "Felvétel a következőbe\n" "%s %s" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "(Várakoztatva)" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Kérem, adja meg a bejelentkezési információt %s -hoz" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Beérkező hívás" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Hívott neve" @@ -792,89 +822,90 @@ msgid "_Options" msgstr "_Beállítások" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Proxy/Regisztráció konfigurációs doboz" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "Videó indítása mindig" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Saját nézet" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "_Segítség" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "Hibakeresési ablak mutatása" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "_Honlap" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "Frissítések keresése" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "Fiók varázsló" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "Adja meg a SIP címet vagy a telefonszámot:" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "Új hívás kezdeményezése" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "Partnerek" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Hozzáadás" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Szerkesztés" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Keresés" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "Partnerek hozzáadása könyvtárból" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "Partner hozzáadása" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Recent calls" msgstr "Legutóbbi hívások" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Jelenlegi identitásom:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Felhasználónév" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Jelszó" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Internet kapcsolat:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Jelentkeztessen be automatikusan" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "Felhasználó azonosító" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Bejelentkezési információ" @@ -922,6 +953,7 @@ msgstr "" "használja." #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -934,6 +966,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "francia: Simon Morlat\n" "angol: Simon Morlat és Delphine Perreau\n" @@ -979,10 +1012,6 @@ msgstr "Linphone - Hitelesítés szükséges" msgid "Please enter the domain password" msgstr "Kérem adja meg a tartomány jelszavát" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "Felhasználó azonosító" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Híváselőzmények" @@ -1020,270 +1049,316 @@ msgid "Looks like sip:" 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 msgid "Registration duration (sec):" msgstr "Regisztrálási Időköz (mp):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Út (nem kötelező):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Út (nem kötelező):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Átvitel" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "Regisztráció" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Jelenléti információ közlése" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "SIP fiók beállítása" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "alapértelmezett hangkártya" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "egy hangkártya" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "alapértelmezett kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Audió kódekek" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Videó kódekek" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "C" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "SIP (TCP)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "SIP (TLS)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Beállítások" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Maximum Továbbítási Egység beállítása:" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "DTMF küldése SIP infóként" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "IPv6 használata IPv4 helyett" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Átvitel" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "Média titkosítás típusa" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "Videó RTP/UDP:" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "Audió RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "DSCP mezők" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "Javítva" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "Alagút" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "Média titkosítás kötelező" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "Alagút" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "DSCP mezők" + +#: ../gtk/parameters.ui.h:26 +#, fuzzy +msgid "SIP/TCP port" +msgstr "SIP port" + +#: ../gtk/parameters.ui.h:27 +#, fuzzy +msgid "SIP/UDP port" +msgstr "SIP port" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "Hálózati protokoll és port" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Közvetlen Internet kapcsolat" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "NAT / tűzfal mögött (adja meg az átjáró IP címét)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Publikus IP cím:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "NAT / tűzfal mögött (STUN használata a feloldáshoz)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 msgid "Behind NAT / Firewall (use ICE)" msgstr "NAT / tűzfal mögött (ICE használata)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 msgid "Behind NAT / Firewall (use uPnP)" msgstr "NAT / tűzfal mögött (uPnP használata)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Publikus IP cím:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "STUN kiszolgáló:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT és tűzfal" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Hálózati beállítások" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Csengőhang:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "Különleges ALSA eszköz (nem kötelező):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Felvevő hang eszköz:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Csengőhang eszköz:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Lejátszó hang eszköz:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Visszhang-elnyomás engedélyezése" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Audió" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Videó bemeneti eszköz:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Kívánt videó felbontás:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Videó bemeneti eszköz:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Videó" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Multimédia beállítások" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "Ez a rész határozza meg az Ön SIP címét, amikor nem használ SIP fiókot" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Az Ön megjelenített neve (pl. Kis József):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Az Ön felhasználóneve:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Az Ön így keletkezett SIP címe:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Alapértelmezett identitás" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "Varázsló" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Hozzáadás" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Szerkesztés" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Eltávolítás" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Proxy fiókok" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Minden kulcsszó törlése" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Titoktartás" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "SIP fiókok beállítása" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Engedélyezés" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Tiltás" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Kódekek" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "A 0 jelentése \"végtelen\"" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Feltöltési sebesség korlát (kbit/mp):" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Letöltési sebesség korlát (kbit/mp):" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "Alkalmazkodó mérték-szabályozás engedélyezése" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1291,31 +1366,54 @@ 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 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Sávszélesség szabályozása" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "Kódekek" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Nyelv" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Haladó beállítások megjelenítése" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "Szint" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Felhasználói környezet" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Sip cím:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Hitelesítési információ" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "címke" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Proxy fiókok" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Kész" @@ -1340,7 +1438,8 @@ msgid "Please wait" msgstr "Kérem várjon" #: ../gtk/dscp_settings.ui.h:1 -msgid "Dscp settings" +#, fuzzy +msgid "DSCP settings" msgstr "DSCP beállítások" #: ../gtk/dscp_settings.ui.h:2 @@ -1392,6 +1491,15 @@ msgid "Round trip time" msgstr "Körbeérés ideje" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Kívánt videó felbontás:" + +#: ../gtk/call_statistics.ui.h:11 msgid "Call statistics and information" msgstr "Hívási statisztika és információ" @@ -1475,19 +1583,142 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Beállítások" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "uPnP nem elérhető" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Kódekek" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +#, fuzzy +msgid "Realm" +msgstr "tartomány:" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Audió" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "Sip cím:" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Keres valakit" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Videó" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Kapcsolódás..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "megszakítva" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "befejezve" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "elhibázva" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1502,102 +1733,77 @@ msgstr "" "Állapot: %s\n" "Időtartam: %i perc %i másodperc\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Kimenő hívás" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Kész" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Információk" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Telefonszám-cél keresése..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Nem sikkerült értelmezni a számot." -#: ../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:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Kapcsolódás" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "Nem sikerült hívni" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 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:2752 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "kapcsolatba lépett veled." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "és automatikus választ kért." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "A hívási jellemzők módosítása..." -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Kapcsolódva." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "Hívás megszakítva" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "Nem sikerült várakoztatni a hívást" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "Jelenlegi hívás várakoztatásának aktiválása..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"A számítógéped úgy tűnik, hogy ALSA hangot használ.\n" -"Ez a legjobb választás. Mindazonáltal a pcm* OSS emuláció modulra\n" -" a linphone-nak szüksége van és ez hiányzik. Kérem futassa le a\n" -"'modprobe snd-pcm-oss' parancsot rendszergazdaként." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"A számítógéped úgy tűnik, hogy ALSA hangot használ.\n" -"Ez a legjobb választás. Mindazonáltal a mixer OSS emuláció modulra\n" -" a linphone-nak szüksége van és ez hiányzik. Kérem futassa le a\n" -"'modprobe snd-pcm-oss' parancsot rendszergazdaként." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "Stun keresés folyamatban..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "ICE helyi jelentkezők begyűjtése folyamatban..." @@ -1646,10 +1852,15 @@ msgid "Pending" msgstr "Függőben" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Időtartam" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Ismeretlen programhiba" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1657,7 +1868,7 @@ msgstr "" "Az Ön által megadott SIP proxy cím érvénytelen. \"sip:\"-tal kell kezdődnie, " "ezt egy hosztnév követi." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1666,132 +1877,162 @@ msgstr "" "Így kéne kinéznie: sip:felhasznalonev@proxytartomany, például sip:" "aladar@pelda.hu" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "Nem sikerült belépni ezzel: %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "Távoli csengés." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "Távoli csengés..." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "Korai médiák." -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "A hívás a következővel: %s várakoztatva" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "%s fogadta a hívást - várakoztatva." -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "Hívás visszatért" -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "%s válaszolt a hívásra." -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 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:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "Visszatértünk." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "Megállítva a másik fél által." -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "A hívás távolról frissítve." -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "A hívás befejezve." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "A felhasználó foglalt." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "A felhasználó ideiglenesen nem elérhető" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "A felhasználó nem akarja, hogy zavarják." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Hívás elutasítva" -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "Nincs válasz." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "Protokol hiba." -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "Átirányítva" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "Nem kompatibilis médiajellemzők." -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "Nem sikerült a hívás." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "A regisztáció a %s -n sikerült." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "A kiregisztrálás kész a következőn: %s ." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "időtúllépés után nincs válasz" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "A regisztáció a %s -n nem sikerült: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, c-format msgid "Authentication token is %s" msgstr "Hitelesítési jel: %s" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, 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 "" +#~ "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" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "A számítógéped úgy tűnik, hogy ALSA hangot használ.\n" +#~ "Ez a legjobb választás. Mindazonáltal a pcm* OSS emuláció modulra\n" +#~ " a linphone-nak szüksége van és ez hiányzik. Kérem futassa le a\n" +#~ "'modprobe snd-pcm-oss' parancsot rendszergazdaként." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "A számítógéped úgy tűnik, hogy ALSA hangot használ.\n" +#~ "Ez a legjobb választás. Mindazonáltal a mixer OSS emuláció modulra\n" +#~ " a linphone-nak szüksége van és ez hiányzik. Kérem futassa le a\n" +#~ "'modprobe snd-pcm-oss' parancsot rendszergazdaként." #~ msgid "Chat with %s" #~ msgstr "Chat-elés %s -el" @@ -1800,18 +2041,10 @@ msgstr[0] "Van %i nem fogadott hivás." #~ msgid "Choosing a username" #~ msgstr "felhasználónév:" -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Információk" - #, fuzzy #~ msgid "Enable video" #~ msgstr "Engedélyezve" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Hitelesítési információ" - #, fuzzy #~ msgid "Unmute" #~ msgstr "Korlátlan" @@ -1861,10 +2094,6 @@ msgstr[0] "Van %i nem fogadott hivás." #~ "linphone mindig az IPv4-et használja. Frissítsd a konfigurációdat, ha " #~ "használni akarod az IPv6-ot" -#, fuzzy -#~ msgid "Incoming call from %s" -#~ msgstr "Beérkező hívás" - #, fuzzy #~ msgid "_Modes" #~ msgstr "Kodekek" @@ -1944,10 +2173,6 @@ msgstr[0] "Van %i nem fogadott hivás." #~ msgid "Closed" #~ msgstr "Lezárva" -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Sip cím:" - #, fuzzy #~ msgid "_View" #~ msgstr "Video" @@ -2185,9 +2410,6 @@ msgstr[0] "Van %i nem fogadott hivás." #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "Erősen ajánlott az 5060-as port használata." -#~ msgid "SIP port" -#~ msgstr "SIP port" - #~ msgid "@" #~ msgstr "@" @@ -2231,9 +2453,6 @@ msgstr[0] "Van %i nem fogadott hivás." #~ msgid "None." #~ msgstr "Nincs." -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Proxy/Regisztráció konfigurációs doboz" - #~ msgid "Send registration:" #~ msgstr "Regisztárció küldés:" @@ -2261,9 +2480,6 @@ msgstr[0] "Van %i nem fogadott hivás." #~ msgid "userid:" #~ msgstr "felhasználói azonosító:" -#~ msgid "realm:" -#~ msgstr "tartomány:" - #~ msgid "Text:" #~ msgstr "Szöveg:" diff --git a/po/it.po b/po/it.po index e7c8cfc13..7328350ac 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" "Last-Translator: Matteo Piazza \n" "Language-Team: it \n" @@ -15,12 +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:969 #, c-format msgid "Call %s" msgstr "Chiamata %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Invia testo a %s" @@ -98,46 +98,51 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "Contatto SIP non valido" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Informazioni" + +#: ../gtk/main.c:573 #, fuzzy, c-format msgid "Call with %s" msgstr "Chat con %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -149,237 +154,238 @@ msgstr "" "veda il tuo stato o aggiungerlo alla tua lista dei contatti Se rispondi no " "questo utente sarà momentaneamente bloccato." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "Prego inserire la password per username %s e dominio %s" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "Cronologia" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Chiamata terminata" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Chimata in entrata" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Rifiuta" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "annullato" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Porte" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Presenza" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "Chiamata %s" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Cerca contatti nella directory %s" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Modifica contatto %s" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Elimina contatto %s" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Elimina contatto %s" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Aggiungi nuovo contatto dalla directory %s" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Stato" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Bitrate Min (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parametri" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Attivato" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Disattivato" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Account" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "Inglese" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Francese" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Svedese" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Italiano" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Spagnolo" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Polacco" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Tedesco" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Russo" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "Giapponese" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Olandese" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Ungherese" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Ceco" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 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:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -446,109 +452,118 @@ msgstr "Ho gia un account e voglio usarlo" msgid "I have already a sip account and I just want to use it" msgstr "Ho gia un account e voglio usarlo" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Manuale utente" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Password:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "Username" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "Password" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "Manuale utente" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "Password:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Grazie. Il tuo account è configurato e pronto all'uso" -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Configuratore di account" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Benvenuto nel configuratore di account" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Configuratore di account" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Configurazione SIP account" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 #, fuzzy msgid "Terminating" msgstr "Termina chiamata" @@ -619,137 +634,152 @@ msgstr "Filtro ICE" msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 #, fuzzy msgid "Calling..." msgstr "Linguaggio" -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 #, fuzzy msgid "Incoming call" msgstr "Chimata in entrata" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 #, fuzzy msgid "In call" msgstr "In chiamata con" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 #, fuzzy msgid "Paused call" msgstr "Termina chiamata" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Chiamata terminata." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Chiamata rifiutata" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Prego inserire le proprie credenziali di accesso per %s" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Chiamata proveniente da %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -796,95 +826,96 @@ msgid "_Options" msgstr "" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Informazioni" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Self-view abilitato" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 #, fuzzy msgid "Show debug window" msgstr "Linphone debug window" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "Account assistant" msgstr "Configuratore di account" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "Indirizzo sip o numero." -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 #, fuzzy msgid "Contacts" msgstr "In connessione" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Aggiungi" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Edita" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Add contacts from directory" msgstr "Aggiungi nuovo contatto dalla directory %s" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contact" msgstr "Trovato %i contatto" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "In chiamata" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Identità corrente" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Username" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Password" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Connessione Internet:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Login Automatico" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Credenziali di accesso" @@ -949,6 +980,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -984,10 +1016,6 @@ msgstr "Linphone - Autenticazione richiesta" msgid "Please enter the domain password" msgstr "Prego inserire la password di dominio" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Cronologia" @@ -1026,314 +1054,381 @@ msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Rotta (opzionale)" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Durata registrazione (sec)" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Rotta (opzionale)" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Rotta (opzionale)" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Transporto" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Pubblica stato della presenza" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "Configurazione SIP account" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "default scheda audio" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 #, fuzzy msgid "a sound card" msgstr "una scheda audio\n" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "default videocamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 #, fuzzy msgid "Audio codecs" msgstr "" "Audio codecs\n" "Video codecs" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 #, fuzzy msgid "Video codecs" msgstr "" "Audio codecs\n" "Video codecs" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "C" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 #, fuzzy msgid "SIP (UDP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 #, fuzzy msgid "SIP (TCP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 #, fuzzy msgid "SIP (TLS)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Preferenze" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Imposta Maximum Transmission Unit:" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "Invia DTMF come SIP info" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "Usa IPv6 invece che IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Transporto" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "Video RTP/UDP" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "Audio RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:26 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:27 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Connessione diretta a internet" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "Dietro NAT / Firewall (IP del gateway)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Indirizzo ip pubblico:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Dietro NAT / Firewall (utilizza STUN)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 #, fuzzy msgid "Behind NAT / Firewall (use ICE)" msgstr "Dietro NAT / Firewall (utilizza STUN)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "Dietro NAT / Firewall (utilizza STUN)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Indirizzo ip pubblico:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "Stun server:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT and Firewall" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Impostazioni di rete" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Suoneria:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "Dispositivo ALSA (optional):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Dispositivo microfono:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Dispositivo squillo:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Dispositivo uscita audio:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Attiva cancellazione eco" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Audio" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Dispositivo Video:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Risoluzione video preferita" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Dispositivo Video:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Video" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Impostazioni multimediali" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" "questa sezione definisce il tuo indirizzo SIP se non hai account attivi" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Nome visualizzato (es: Mario Rossi):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Username" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Il tuo indirizzo sip:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Identità di default" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Aggiungi" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Edita" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Rimuovi" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Account proxy" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Cancella tutte le password" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Privacy" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "Gestici SIP Account" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Attivato" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Disattivato" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 sta per illimitato" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Velocità massima in upload Kbit/sec:" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Velocita massima in Dowload Kbit/sec" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Gestione banda" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "Codec" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Linguaggio" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 #, fuzzy msgid "Level" msgstr "Linguaggio" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Interfaccia utente" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Indirizzi SIP" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Linphone - Autenticazione richiesta" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "etichetta" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Account proxy" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Fatto" @@ -1359,7 +1454,7 @@ msgstr "Prego attendere" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Preferenze" #: ../gtk/dscp_settings.ui.h:2 @@ -1420,6 +1515,15 @@ msgid "Round trip time" msgstr "" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Risoluzione video preferita" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Contact informazioni" @@ -1505,19 +1609,140 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Preferenze" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Codecs" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Audio" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "Indirizzi SIP" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Cerca" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Video" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "In connessione..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "annullato" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "comletato" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "mancante" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1532,108 +1757,82 @@ msgstr "" "Stato: %s\n" "Durata: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Chiamata in uscita" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Pronto" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Informazioni" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Ricerca numero destinazione..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Impossibile risolvere il numero." -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Errore nel formato del contatto sip. Usualmente un indirizzo appare sip:" -"user@domain" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "In connessione" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 #, fuzzy msgid "Could not call" msgstr "chiamata fallita" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 #, fuzzy msgid "is contacting you" msgstr "ti sta conttatando." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Connessione" -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 #, fuzzy msgid "Call aborted" msgstr "annullato" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 #, fuzzy msgid "Could not pause the call" msgstr "chiamata fallita" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 #, fuzzy msgid "Pausing the current call..." msgstr "Mostra chiamata corrente" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Il tuo computer appare utlizzare il driver ALSA.\n" -"Questa è la scelta migliore. Tuttavia il modulo di emulazione pcm oss\n" -"è assente e linphone lo richede. Prego eseguire\n" -"'modprobe snd-pcm-oss' da utente root per caricarlo." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Il tuo computer appare utlizzare il driver ALSA.\n" -"Questa è la scelta migliore. Tuttavia il modulo di emulazione mixer oss\n" -"è assente e linphone lo richede. Prego eseguire\n" -"'modprobe snd-mixer-oss' da utente root per caricarlo." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "Ricerca Stun in progresso ..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1682,10 +1881,15 @@ msgid "Pending" msgstr "Pendente" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Durata" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Bug-sconosciuto" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1693,7 +1897,7 @@ msgstr "" "L'indirizzo sip proxy utilizzato è invalido, deve iniziare con \"sip:\" " "seguito dall' hostaname." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1701,136 +1905,166 @@ msgstr "" "L'identità sip utilizza è invalida.\n" "Dovrebbre essere sip:username@proxydomain, esempio: sip:alice@example.net" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "impossibile login come %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "" -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "" -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Chat con %s" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 #, fuzzy msgid "Call resumed." msgstr "Chiamata terminata" -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Chiamata terminata." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Utente occupato" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Utente non disponibile" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "L'utente non vuole essere disturbato" -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 #, fuzzy msgid "No response." msgstr "timeout no risposta" -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 #, fuzzy msgid "Redirected" msgstr "Rediretto verso %s..." -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 #, fuzzy msgid "Call failed." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Registrazione su %s attiva" -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "Unregistrazione su %s" -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "timeout no risposta" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrazione su %s fallita: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Linphone - Autenticazione richiesta" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "" msgstr[1] "" -#~ msgid "label" -#~ msgstr "etichetta" +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "Errore nel formato del contatto sip. Usualmente un indirizzo appare sip:" +#~ "user@domain" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Il tuo computer appare utlizzare il driver ALSA.\n" +#~ "Questa è la scelta migliore. Tuttavia il modulo di emulazione pcm oss\n" +#~ "è assente e linphone lo richede. Prego eseguire\n" +#~ "'modprobe snd-pcm-oss' da utente root per caricarlo." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Il tuo computer appare utlizzare il driver ALSA.\n" +#~ "Questa è la scelta migliore. Tuttavia il modulo di emulazione mixer oss\n" +#~ "è assente e linphone lo richede. Prego eseguire\n" +#~ "'modprobe snd-mixer-oss' da utente root per caricarlo." #~ msgid "Chat with %s" #~ msgstr "Chat con %s" @@ -1859,9 +2093,6 @@ msgstr[1] "" #~ msgid "Verifying" #~ msgstr "Verifica" -#~ msgid "Confirmation" -#~ msgstr "Informazioni" - #~ msgid "Creating your account" #~ msgstr "Creazione account" @@ -1885,10 +2116,6 @@ msgstr[1] "" #~ "Registrati a FONICS\n" #~ "virtual network !" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Linphone - Autenticazione richiesta" - #~ msgid "Unmute" #~ msgstr "" #~ "Attiva\n" @@ -2118,9 +2345,6 @@ msgstr[1] "" #~ msgid "Sound playback filter for MacOS X Core Audio drivers" #~ msgstr "Sound playback filter for MacOS X Core Audio drivers" -#~ msgid "Incoming call from %s" -#~ msgstr "Chiamata proveniente da %s" - #~ msgid "Assistant" #~ msgstr "Configuratore" @@ -2213,8 +2437,5 @@ msgstr[1] "" #~ msgid "Unknown" #~ msgstr "Sconosciuto" -#~ msgid "SIP address" -#~ msgstr "Indirizzi SIP" - #~ msgid "Bresilian" #~ msgstr "Brasiliano" diff --git a/po/ja.po b/po/ja.po index 56362238b..900fc6cc3 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2003-01-21 00:05+9000\n" "Last-Translator: YAMAGUCHI YOSHIYA \n" "Language-Team: \n" @@ -17,12 +17,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:969 #, c-format msgid "Call %s" msgstr "" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "" @@ -96,46 +96,51 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "pixmapファイルが見つかりません %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "情報" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -144,242 +149,243 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1023 +#: ../gtk/main.c:1227 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 #, fuzzy msgid "Call ended" msgstr "通話は拒否されました。" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "ライン入力" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "接続中" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 #, fuzzy msgid "Add to addressbook" msgstr "電話帳" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 #, fuzzy msgid "Presence status" msgstr "状態" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名前" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "通話はキャンセルされました。" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "(接続するための情報がありません!)" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, c-format msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "状態" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "最低限のビットレート (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "パラメーター" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "使用する" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "使用しない" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Magyar" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "čeština" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "简体中文" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 #, fuzzy msgid "None" msgstr "ありません。" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -441,110 +447,118 @@ msgstr "" msgid "I have already a sip account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 #, fuzzy msgid "Username:" msgstr "ユーザーマニュアル" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 #, fuzzy msgid "Password:" msgstr "パスワード" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "ユーザーマニュアル" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "パスワード" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "ユーザーマニュアル" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "パスワード" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "" -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "" @@ -613,138 +627,153 @@ msgstr "通話はキャンセルされました。" msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 #, fuzzy msgid "Calling..." msgstr "接続中" -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 #, fuzzy msgid "Incoming call" msgstr "接続中" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 #, fuzzy msgid "In call" msgstr "接続中" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 #, fuzzy msgid "Paused call" msgstr "接続中" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 #, fuzzy msgid "Call ended." msgstr "通話は拒否されました。" -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "通話はキャンセルされました。" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -794,98 +823,99 @@ msgid "_Options" msgstr "" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "情報" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "Enable self-view" msgstr "使用する" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 #, fuzzy msgid "SIP address or phone number:" msgstr "レジストラサーバーのSIPアドレス" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 #, fuzzy msgid "Contacts" msgstr "接続中" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "追加する" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Add contacts from directory" msgstr "コーデックの情報" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contact" msgstr "(接続するための情報がありません!)" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "接続中" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "My current identity:" msgstr "個人情報" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "ユーザーマニュアル" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "パスワード" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + #: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" @@ -948,6 +978,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -985,10 +1016,6 @@ msgstr "コーデックの情報" msgid "Please enter the domain password" msgstr "" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "" @@ -1028,326 +1055,393 @@ msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:8 #, fuzzy msgid "Registration duration (sec):" msgstr "登録しました。" +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "Route (optional):" msgstr "" #: ../gtk/sip_account.ui.h:10 #, fuzzy +msgid "Transport" +msgstr "接続中" + +#: ../gtk/sip_account.ui.h:11 +msgid "Register" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +#, fuzzy msgid "Publish presence information" msgstr "コーデックの情報" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "" #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" +msgid "anonymous" msgstr "" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" +msgid "GSSAPI" msgstr "" #: ../gtk/parameters.ui.h:3 -msgid "default camera" +msgid "SASL" msgstr "" #: ../gtk/parameters.ui.h:4 -msgid "CIF" +msgid "default soundcard" msgstr "" #: ../gtk/parameters.ui.h:5 +msgid "a sound card" +msgstr "" + +#: ../gtk/parameters.ui.h:6 +msgid "default camera" +msgstr "" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "" + +#: ../gtk/parameters.ui.h:8 #, fuzzy msgid "Audio codecs" msgstr "オーディオコーデックのプロパティー" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 #, fuzzy msgid "Video codecs" msgstr "オーディオコーデックのプロパティー" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 #, fuzzy msgid "Transport" msgstr "接続中" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 -msgid "Network protocol and ports" -msgstr "" - #: ../gtk/parameters.ui.h:24 -msgid "Direct connection to the Internet" +msgid "Tunnel" msgstr "" #: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +msgid "DSCP fields" msgstr "" #: ../gtk/parameters.ui.h:26 #, fuzzy -msgid "Public IP address:" -msgstr "Sipアドレス:" +msgid "SIP/TCP port" +msgstr "SIPのポート" #: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" +#, fuzzy +msgid "SIP/UDP port" +msgstr "SIPのポート" #: ../gtk/parameters.ui.h:28 -msgid "Behind NAT / Firewall (use ICE)" +msgid "Network protocol and ports" msgstr "" #: ../gtk/parameters.ui.h:29 -msgid "Behind NAT / Firewall (use uPnP)" +msgid "Direct connection to the Internet" msgstr "" #: ../gtk/parameters.ui.h:30 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:33 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:34 +#, fuzzy +msgid "Public IP address:" +msgstr "Sipアドレス:" + +#: ../gtk/parameters.ui.h:35 #, fuzzy msgid "Stun server:" msgstr "使用するサウンドデバイス" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 #, fuzzy msgid "NAT and Firewall" msgstr "接続中" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 #, fuzzy msgid "Network settings" msgstr "ネットワーク" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 #, fuzzy msgid "Ring sound:" msgstr "録音する音源" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 #, fuzzy msgid "Capture device:" msgstr "使用するサウンドデバイス" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 #, fuzzy msgid "Ring device:" msgstr "使用するサウンドデバイス" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 #, fuzzy msgid "Playback device:" msgstr "使用するサウンドデバイス" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 #, fuzzy msgid "Audio" msgstr "接続中" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 #, fuzzy msgid "Video input device:" msgstr "使用するサウンドデバイス" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "使用するサウンドデバイス" + +#: ../gtk/parameters.ui.h:48 #, fuzzy msgid "Video" msgstr "接続中" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 #, fuzzy msgid "Your username:" msgstr "ユーザーマニュアル" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 #, fuzzy msgid "Your resulting SIP address:" msgstr "あなたのSIPアドレス" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 #, fuzzy msgid "Default identity" msgstr "個人情報" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "追加する" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "削除する" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 #, fuzzy msgid "Proxy accounts" msgstr "接続中" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 #, fuzzy msgid "Privacy" msgstr "接続中" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "使用する" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "使用しない" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 #, fuzzy msgid "Codecs" msgstr "接続中" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 #, fuzzy msgid "Codecs" msgstr "コーデック" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 #, fuzzy msgid "Language" msgstr "接続中" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 #, fuzzy msgid "Level" msgstr "接続中" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 #, fuzzy msgid "User interface" msgstr "ユーザーマニュアル" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "サーバーのアドレス" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "コーデックの情報" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "接続中" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 #, fuzzy msgid "Done" msgstr "ありません。" @@ -1377,7 +1471,7 @@ msgstr "" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "ネットワーク" #: ../gtk/dscp_settings.ui.h:2 @@ -1432,6 +1526,14 @@ msgid "Round trip time" msgstr "サウンドのプロパティー" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "コーデックの情報" @@ -1516,19 +1618,141 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "ネットワーク" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "特に情報はありません" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "接続中" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "接続中" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "アドレス" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "接続中" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "接続中" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "コネクション" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1538,109 +1762,82 @@ msgid "" "Duration: %i mn %i sec\n" msgstr "" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 #, fuzzy msgid "Ready" msgstr "準備完了。" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "情報" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "" -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "" -#: ../coreapi/linphonecore.c:2252 -#, fuzzy -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"SIPアドレスの形式エラーです。SIPアドレスは、のような" -"形式です。" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 #, fuzzy msgid "Contacting" msgstr "接続中" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 #, fuzzy msgid "Could not call" msgstr "pixmapファイルが見つかりません %s" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 #, fuzzy msgid "is contacting you" msgstr "から電話です。" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "接続しました。" -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 #, fuzzy msgid "Call aborted" msgstr "通話はキャンセルされました。" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"このコンピューターはALSAサウンドドライバーを使用しているようです。\n" -"それは最良の選択です。しかし、Linphoneが必要とする\n" -"pcm ossエミュレーションモジュールが見つかりません。\n" -"ロードするために、ルート権限で'modprobe snd-pcm-oss'を実行してください。" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"このコンピューターはALSAサウンドドライバーを使用しているようです。\n" -"それは最良の選択です。しかし、Linphoneが必要とする\n" -"mixer ossエミュレーションモジュールが見つかりません。\n" -"ロードするために、ルート権限で'modprobe snd-mixer-oss'を実行してください。" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1693,146 +1890,155 @@ msgid "Pending" msgstr "" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "情報" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, fuzzy, c-format msgid "Could not login as %s" msgstr "pixmapファイルが見つかりません %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 #, fuzzy msgid "Remote ringing." msgstr "登録中……" -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 #, fuzzy msgid "Remote ringing..." msgstr "登録中……" -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 #, fuzzy msgid "Call resumed." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "電話をかける\n" "電話に出る" -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 #, fuzzy msgid "Call terminated." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "ユーザーはビジーです" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "ユーザーは、今出られません。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "ユーザーは手が離せないようです。" -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 #, fuzzy msgid "Call failed." msgstr "通話はキャンセルされました。" -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "登録しました。" -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "登録しました。" -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "登録しました。" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "コーデックの情報" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1840,17 +2046,39 @@ msgstr[0] "" msgstr[1] "" #, fuzzy -#~ msgid "Confirmation" -#~ msgstr "情報" +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "SIPアドレスの形式エラーです。SIPアドレスは、のよ" +#~ "うな形式です。" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "このコンピューターはALSAサウンドドライバーを使用しているようです。\n" +#~ "それは最良の選択です。しかし、Linphoneが必要とする\n" +#~ "pcm ossエミュレーションモジュールが見つかりません。\n" +#~ "ロードするために、ルート権限で'modprobe snd-pcm-oss'を実行してください。" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "このコンピューターはALSAサウンドドライバーを使用しているようです。\n" +#~ "それは最良の選択です。しかし、Linphoneが必要とする\n" +#~ "mixer ossエミュレーションモジュールが見つかりません。\n" +#~ "ロードするために、ルート権限で'modprobe snd-mixer-oss'を実行してください。" #, fuzzy #~ msgid "Enable video" #~ msgstr "使用する" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "コーデックの情報" - #, fuzzy #~ msgid "Contact list" #~ msgstr "接続中" @@ -1921,10 +2149,6 @@ msgstr[1] "" #~ msgid "Gone" #~ msgstr "ありません。" -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "アドレス" - #, fuzzy #~ msgid "Display filters" #~ msgstr "表示される名前" @@ -2018,9 +2242,6 @@ msgstr[1] "" #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "5060番ポートを使うことを強く推奨します。" -#~ msgid "SIP port" -#~ msgstr "SIPのポート" - #~ msgid "@" #~ msgstr "@" @@ -2075,10 +2296,6 @@ msgstr[1] "" #~ msgid "Communication ended." #~ msgstr "会話は終了しました。" -#, fuzzy -#~ msgid "Server address" -#~ msgstr "サーバーのアドレス" - #~ msgid "28k modem" #~ msgstr "28kのモデム" diff --git a/po/nb_NO.po b/po/nb_NO.po index 470e0d024..d6eeac5c0 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2011-04-05 01:56+0200\n" "Last-Translator: Øyvind Sæther \n" "Language-Team: Norwegian Bokmål \n" @@ -17,12 +17,12 @@ msgstr "" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "Ring %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Send tekst til %s" @@ -98,35 +98,35 @@ msgstr "Skru mikrofonen av" msgid "Couldn't find pixmap file: %s" msgstr "Fant ikke pixmap fli: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "Ugyldig SIP kontakt !" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "skriv logg-informasjon under kjøring" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "Start skjult i systemkurven, ikke vis programbildet." -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "address som skal ringes nå" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "besvarer innkommende samtaler automatisk om valgt" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -134,12 +134,17 @@ msgstr "" "Spesifiser arbeidsmappe (bør være base for installasjonen, f.eks: c:" "\\Programfiler\\Linphone)" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Bekreftelse" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Ring med %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -152,70 +157,70 @@ msgstr "" "din kontaktliste?\n" "Hvis du svarer nei vil personen bli svartelyst midlertidig." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Skriv inn ditt passord for brukernavn %s\n" " på domene %s:i>:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "Samtalehistorikk" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Samtale avsluttet" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Svarer" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Avvis" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "Samtale avbrutt" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Porter" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Peker til nettsted" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - en video Internet telefon" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (Standard)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "Vi er overført til %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -223,170 +228,171 @@ msgstr "" "Klarte ikke å finne noe lydkort på denne datamaskinen.\n" "Du vil ikke kunne sende eller motta lydsamtaler." -#: ../gtk/main.c:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Tilstedestatus" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Navn" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "Ring %s" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Søk i %s katalogen" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Rediger kontakt '%s'" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Slett kontakt '%s'" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Slett kontakt '%s'" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Legg til kontakt fra %s katalogen" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Frekvens (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Min. datahastighet (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parametere" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "På" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Av" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "Engelsk" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Fransk" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Svensk" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Italisensk" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Spansk" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "Portugisisk" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Polsk" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Tysk" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Russisk" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "Japansk" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Nederlandsk" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Ungarsk" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Tjekkisk" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "Kinesisk" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 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:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -453,109 +459,118 @@ msgstr "Jeg har allerede en brukerkonto og vil bruke den." msgid "I have already a sip account and I just want to use it" msgstr "Jeg har allerede en brukerkonto og vil bruke den." -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Brukernavn:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Passord:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "Brukernavn" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "Passord" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "Brukernavn:" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "Passord:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Takk. Ditt konto er nå satt opp og klart til bruk." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Brukerkontoveiviser" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Velkommen til brukerkontoveiviseren" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Brukerkontoveiviser" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Konfigurer en SIP konto" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 #, fuzzy msgid "Terminating" msgstr "Lägg på" @@ -627,135 +642,150 @@ msgstr "ICE filter" msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "I samtale med" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "Pauset samtale" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Samtale avsluttet." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 #, fuzzy msgid "Transfer done." msgstr "Overfører" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Overfører" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "Fortsett" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, fuzzy msgid "(Paused)" msgstr "Pause" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Skriv inn påloggingsinformasjon for %s:" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Inkommande samtal från %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -802,91 +832,92 @@ msgid "_Options" msgstr "_Alternativer" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Bekreftelse" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Vis video av deg selv" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "_Hjelp" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "Vis avlusningsvindu" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "H_jemmeside" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "Sjekk _Oppdateringer" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "Account assistant" msgstr "Brukerkontoveiviser" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "Sip adresse eller telefonnummer:" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "Start en ny samtale" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "Kontakter" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Legg til" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Rediger" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Søk" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "Legg til kontakter fra katalogen" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "Legg til kontakt" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "I samtale" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Min nåværende identitet:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Brukernavn" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Passord" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Internet forbindelse:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Logg meg på automatisk" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "BrukerID" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Innlogginsinformasjon" @@ -934,6 +965,7 @@ msgstr "" "(rfc3261)." #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -946,6 +978,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat og Delphine Perreau\n" @@ -991,10 +1024,6 @@ msgstr "Linphone - Autorisering kreves" msgid "Please enter the domain password" msgstr "Skriv inn passordet for domenet" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "BrukerID" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Samtalehistorikk" @@ -1032,305 +1061,372 @@ msgid "Looks like sip:" msgstr "Ser ut som sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (valgfritt):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Registreringsfrekvens (sek.):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Route (valgfritt):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Route (valgfritt):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Transport" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Publiser tilstedestatus" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "Konfigurer en SIP konto" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "standard lydkort" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "ett lydkort" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "standard kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Lyd kodek" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Video kodek" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "C" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 #, fuzzy msgid "SIP (UDP)" msgstr "SIP (UDP):" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 #, fuzzy msgid "SIP (TCP)" msgstr "SIP (TCP):" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 #, fuzzy msgid "SIP (TLS)" msgstr "SIP (TCP):" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Innstillinger" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Velg MTU (Maximum Transmission Unit):" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "Send DTMF som SIP-info" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "Bruk IPv6 istedet for IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Transport" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "Video RTP/UDP:" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "Lyd RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:26 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:27 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Tilkoblet Internett direkte" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "Bak NAT / Brannmur (spesifiser gateway IP under)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Offentlig IP-addresse:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Bak NAT / Brannmur (bruk STUN for å avgjøre)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 #, fuzzy msgid "Behind NAT / Firewall (use ICE)" msgstr "Bak NAT / Brannmur (bruk STUN for å avgjøre)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "Bak NAT / Brannmur (bruk STUN for å avgjøre)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Offentlig IP-addresse:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "STUN tjener:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT og Brannvegg" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Nettverksinnstillinger" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Ringelyd:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "Spesiell ALSA enhet (valgfritt):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Mikrofonenhet:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Ringe-enhet:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Avspillingsenhet:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Bruk ekko-kansellering" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Lyd" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Videoenhet:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Foretrukke video-oppløsning:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Videoenhet:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Video" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Multimediainnstillinger" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "Denne seksjonen velger SIP-addresse når du ikke bruker en SIP-konto" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Vist navn (eks: Ola Nordmann):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Ditt brukernavn:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Din resulterende SIP addresse:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Standard identitet" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Legg til" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Rediger" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Fjern" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Proxy kontoer" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Slett alle passord" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Personvern" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "Behandle SIP-kontoer" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Aktiver" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Deaktiver" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Kodeker" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 betyr \"ubegrenset\"" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Maks opplastningshastighet i Kbit/sek:" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Nedlastningsbegrensning i Kbit/sek:" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Båndbreddekontrol" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "Kodek" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Språk" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Vis avanserte innstillinger" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "Nivå" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Brukergrensesnitt" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "SIP Adress" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Autorisering kreves" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "etikett" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Proxy kontoer" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Ferdig" @@ -1356,7 +1452,7 @@ msgstr "Vennligst vent" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Innstillinger" #: ../gtk/dscp_settings.ui.h:2 @@ -1413,6 +1509,15 @@ msgid "Round trip time" msgstr "" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Foretrukke video-oppløsning:" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Kontaktinformasjon" @@ -1498,19 +1603,140 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Innstillinger" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Kodeker" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Lyd" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "SIP Adress" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Søk noen" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Video" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Tilknytter..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "avbrutt" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "Fullført" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "ubesvart" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1525,105 +1751,77 @@ msgstr "" "Status: %s\n" "Lengde: %i min %i sek\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Utgående samtale" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Klar" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Bekreftelse" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Ser etter telefonnummer for destinasjonen..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Kan ikke tilkoble dette nummeret." -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Klarer ikke å tolke angitt SIP-adresse. En SIP-adresse er vanligvis ut som " -"sip: brukernavn@domenenavn" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Tilknytter" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "Kunne ikke ringe" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Beklager, du har nådd maksimalt antall samtidige samtaler" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "Kontakter deg." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr " og ba om autosvar." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "Endrer ringeparametre..." -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Tilkoblet" -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "Samtale avbrutt" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "Kunne ikke pause samtalen" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "Pauser nåværende samtale" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Din datamaskin ser ut til å bruke ALSA drivere for lyd.\n" -"Dette er det beste alternativet. Det ser ut til at pcm oss " -"emulasjonsmodulen\n" -"mangler og linphone trenger den. Vennligst kjør\n" -"'modprobe snd-pcm-oss' som root for å laste den." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Din datamaskin ser ut til å bruke ALSA drivere for lyd.\n" -"Dette er det beste alternativet. Det ser ut til at mixermodulen for oss " -"emulering\n" -"mangler og linphone trenger den. Vennligst kjør\n" -"'modprobe snd-mixer-oss' som root for å laste den." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "STUN oppslag pågår..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1672,10 +1870,15 @@ msgid "Pending" msgstr "Pågående" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Varighet" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Ukjent feil" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1683,7 +1886,7 @@ msgstr "" "SIP proxy adressen du har angitt er ugyldig, den må begynne med \"sip:\" " "etterfult av vertsnavn." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1691,134 +1894,166 @@ 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:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "Ikke ikke logge inn som %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 #, fuzzy msgid "Remote ringing..." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "Tidlig media" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "Samtalen med %s er pauset." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "Samtale besvart av %s - på vent." -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "Samtale gjenopptatt." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "Samtale besvart av %s." -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 #, fuzzy msgid "We have been resumed." msgstr "Vi har blitt gjenopptatt..." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Samtale avsluttet." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Brukeren er opptatt." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Brukeren er midlertidig ikke tilgjengelig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "Brukeren vil ikke bli forstyrret." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Samtale avvist." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "Ikke noe svar." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "Protokollfeil." -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "Omdirigert" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "Samtale feilet." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lykkes." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lykkes." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "ingen svar innen angitt tid" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislykkes: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Autorisering kreves" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, 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 "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "Klarer ikke å tolke angitt SIP-adresse. En SIP-adresse er vanligvis ut " +#~ "som sip: brukernavn@domenenavn" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Din datamaskin ser ut til å bruke ALSA drivere for lyd.\n" +#~ "Dette er det beste alternativet. Det ser ut til at pcm oss " +#~ "emulasjonsmodulen\n" +#~ "mangler og linphone trenger den. Vennligst kjør\n" +#~ "'modprobe snd-pcm-oss' som root for å laste den." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Din datamaskin ser ut til å bruke ALSA drivere for lyd.\n" +#~ "Dette er det beste alternativet. Det ser ut til at mixermodulen for oss " +#~ "emulering\n" +#~ "mangler og linphone trenger den. Vennligst kjør\n" +#~ "'modprobe snd-mixer-oss' som root for å laste den." #~ msgid "Keypad" #~ msgstr "Tastatur" @@ -1850,9 +2085,6 @@ msgstr[1] "Du har %i missade samtal" #~ msgid "Verifying" #~ msgstr "Verifiserer" -#~ msgid "Confirmation" -#~ msgstr "Bekreftelse" - #~ msgid "Creating your account" #~ msgstr "Lager brukerkontoen din" @@ -1885,9 +2117,6 @@ msgstr[1] "Du har %i missade samtal" #~ msgid "No common codecs" #~ msgstr "Ingen felles kodek" -#~ msgid "Authentication failure" -#~ msgstr "Autorisering kreves" - #~ msgid "Windows" #~ msgstr "Vinduer" @@ -2157,9 +2386,6 @@ msgstr[1] "Du har %i missade samtal" #~ "Din dator er tilkoblet ett IPv6 nettverk. Linphone bruker IPv6 som " #~ "standard. Oppdater oppsettet om du vil bruke IPv6. " -#~ msgid "Incoming call from %s" -#~ msgstr "Inkommande samtal från %s" - #~ msgid "Assistant" #~ msgstr "Assistent" @@ -2256,9 +2482,6 @@ msgstr[1] "Du har %i missade samtal" #~ msgid "Unknown" #~ msgstr "Okänd" -#~ msgid "SIP address" -#~ msgstr "SIP Adress" - #~ msgid "Bresilian" #~ msgstr "Brasiliansk" diff --git a/po/nl.po b/po/nl.po index fcd4ca42b..26b7a31f5 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2007-09-05 10:40+0200\n" "Last-Translator: Hendrik-Jan Heins \n" "Language-Team: Nederlands \n" @@ -19,12 +19,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:969 #, fuzzy, c-format msgid "Call %s" msgstr "Oproepgeschiedenis" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "" @@ -99,46 +99,51 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Informatie" + +#: ../gtk/main.c:573 #, fuzzy, c-format msgid "Call with %s" msgstr "Chat met %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -147,240 +152,241 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1023 +#: ../gtk/main.c:1227 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "Linphone - Oproepgeschiedenis" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Oproep beeindigd" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "lijn" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "afgebroken" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Contactlijst" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "Een Vrije SIP video-telefoon" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 #, fuzzy msgid "Add to addressbook" msgstr "Adresboek" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Aanwezigheidsstatus" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Naam" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "Oproepgeschiedenis" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 #, fuzzy msgid "Chat" msgstr "Chat box" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Bewerk contactgegevens" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, c-format msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Frequentie (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Minimale bitrate (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parameters" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Aan" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Uit" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Account" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "Geen" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -442,110 +448,118 @@ msgstr "" msgid "I have already a sip account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 #, fuzzy msgid "Username:" msgstr "gebruikersnaam:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 #, fuzzy msgid "Password:" msgstr "wachtwoord:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "gebruikersnaam:" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "wachtwoord:" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "gebruikersnaam:" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "wachtwoord:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "" -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "" @@ -616,138 +630,153 @@ msgstr "Oproep geannuleerd." msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 #, fuzzy msgid "Calling..." msgstr "Contactlijst" -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 #, fuzzy msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 #, fuzzy msgid "In call" msgstr "Contactlijst" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 #, fuzzy msgid "Paused call" msgstr "Contactlijst" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 #, fuzzy msgid "Call ended." msgstr "Oproep beeindigd" -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Oproep geannuleerd." -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Inkomende oproep" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -797,101 +826,101 @@ msgid "_Options" msgstr "" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Proxy/registratieserver registratieveld" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "Enable self-view" msgstr "Video aan" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "_Help" msgstr "Help" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 #, fuzzy msgid "SIP address or phone number:" msgstr "Geef het SIP adres of telefoonnummer in" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 #, fuzzy msgid "Contacts" msgstr "Verbinden" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -#, fuzzy -msgid "Add" -msgstr "Adres" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Bewerken" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Add contacts from directory" msgstr "Contact informatie" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contact" msgstr "Bewerk contactgegevens" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "Inkomende oproep" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "My current identity:" msgstr "SIP-identiteit:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "gebruikersnaam:" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "wachtwoord:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 #, fuzzy msgid "Automatically log me in" msgstr "Automatisch een geldige hostnaam raden" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + #: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" @@ -954,6 +983,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -991,10 +1021,6 @@ msgstr "Authorisatie gevraagd" msgid "Please enter the domain password" msgstr "" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - #: ../gtk/call_logs.ui.h:1 #, fuzzy msgid "Call history" @@ -1036,328 +1062,397 @@ msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (optioneel):" - -#: ../gtk/sip_account.ui.h:8 #, fuzzy msgid "Registration duration (sec):" msgstr "Registratieperiode:" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Route (optioneel):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Route (optioneel):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Contactlijst" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 #, fuzzy msgid "Publish presence information" msgstr "Toon informatie over aanwezigheid:" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "" #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" +msgid "anonymous" msgstr "" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" +msgid "GSSAPI" msgstr "" #: ../gtk/parameters.ui.h:3 -msgid "default camera" +msgid "SASL" msgstr "" #: ../gtk/parameters.ui.h:4 -msgid "CIF" +msgid "default soundcard" msgstr "" #: ../gtk/parameters.ui.h:5 +msgid "a sound card" +msgstr "" + +#: ../gtk/parameters.ui.h:6 +msgid "default camera" +msgstr "" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "" + +#: ../gtk/parameters.ui.h:8 #, fuzzy msgid "Audio codecs" msgstr "Video codecs" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 #, fuzzy msgid "Video codecs" msgstr "Video codecs" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 #, fuzzy msgid "Transport" msgstr "Contactlijst" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 -msgid "Network protocol and ports" -msgstr "" - #: ../gtk/parameters.ui.h:24 -msgid "Direct connection to the Internet" +msgid "Tunnel" msgstr "" #: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +msgid "DSCP fields" msgstr "" #: ../gtk/parameters.ui.h:26 #, fuzzy -msgid "Public IP address:" -msgstr "SIP-adres:" +msgid "SIP/TCP port" +msgstr "SIP-poort" #: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" +#, fuzzy +msgid "SIP/UDP port" +msgstr "SIP-poort" #: ../gtk/parameters.ui.h:28 -msgid "Behind NAT / Firewall (use ICE)" +msgid "Network protocol and ports" msgstr "" #: ../gtk/parameters.ui.h:29 -msgid "Behind NAT / Firewall (use uPnP)" +msgid "Direct connection to the Internet" msgstr "" #: ../gtk/parameters.ui.h:30 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:33 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:34 +#, fuzzy +msgid "Public IP address:" +msgstr "SIP-adres:" + +#: ../gtk/parameters.ui.h:35 #, fuzzy msgid "Stun server:" msgstr "Geluidsapparaat" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 #, fuzzy msgid "NAT and Firewall" msgstr "Contactlijst" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 #, fuzzy msgid "Network settings" msgstr "Netwerk" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 #, fuzzy msgid "Ring sound:" msgstr "Belgeluid:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 #, fuzzy msgid "Capture device:" msgstr "Geluidsapparaat gebruiken:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 #, fuzzy msgid "Ring device:" msgstr "Geluidsapparaat gebruiken:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 #, fuzzy msgid "Playback device:" msgstr "Geluidsapparaat gebruiken:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 #, fuzzy msgid "Audio" msgstr "Contactlijst" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 #, fuzzy msgid "Video input device:" msgstr "Geluidsapparaat" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Geluidsapparaat" + +#: ../gtk/parameters.ui.h:48 #, fuzzy msgid "Video" msgstr "Contactlijst" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 #, fuzzy msgid "Your username:" msgstr "gebruikersnaam:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 #, fuzzy msgid "Your resulting SIP address:" msgstr "Uw SIP-adres:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 #, fuzzy msgid "Default identity" msgstr "SIP-identiteit:" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +#, fuzzy +msgid "Add" +msgstr "Adres" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Bewerken" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Verwijderen" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 #, fuzzy msgid "Proxy accounts" msgstr "Contactlijst" -#: ../gtk/parameters.ui.h:54 -msgid "Erase all passwords" -msgstr "" - -#: ../gtk/parameters.ui.h:55 -#, fuzzy -msgid "Privacy" -msgstr "Contactlijst" - -#: ../gtk/parameters.ui.h:56 -msgid "Manage SIP Accounts" -msgstr "" - -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 -msgid "Enable" -msgstr "Aan" - -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 -msgid "Disable" -msgstr "Uit" - -#: ../gtk/parameters.ui.h:59 -#, fuzzy -msgid "Codecs" -msgstr "Contactlijst" - #: ../gtk/parameters.ui.h:60 -msgid "0 stands for \"unlimited\"" +msgid "Erase all passwords" msgstr "" #: ../gtk/parameters.ui.h:61 #, fuzzy +msgid "Privacy" +msgstr "Contactlijst" + +#: ../gtk/parameters.ui.h:62 +msgid "Manage SIP Accounts" +msgstr "" + +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 +msgid "Enable" +msgstr "Aan" + +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 +msgid "Disable" +msgstr "Uit" + +#: ../gtk/parameters.ui.h:65 +#, fuzzy +msgid "Codecs" +msgstr "Contactlijst" + +#: ../gtk/parameters.ui.h:66 +msgid "0 stands for \"unlimited\"" +msgstr "" + +#: ../gtk/parameters.ui.h:67 +#, fuzzy msgid "Upload speed limit in Kbit/sec:" msgstr "Upload bandbreedte (kbit/sec):" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 #, fuzzy msgid "Download speed limit in Kbit/sec:" msgstr "Download bandbreedte (kbit/sec):" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 #, fuzzy msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 #, fuzzy msgid "Language" msgstr "Contactlijst" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 #, fuzzy msgid "Level" msgstr "Contactlijst" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 #, fuzzy msgid "User interface" msgstr "gebruikersnaam:" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Serveradres" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Authorisatie gegevens" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Contactlijst" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 #, fuzzy msgid "Done" msgstr "Weg" @@ -1387,7 +1482,7 @@ msgstr "" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Netwerk" #: ../gtk/dscp_settings.ui.h:2 @@ -1443,6 +1538,14 @@ msgid "Round trip time" msgstr "Geluidseigenschappen" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Contact informatie" @@ -1527,19 +1630,142 @@ msgstr "" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Netwerk" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "Geen informatie beschikbaar" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Contactlijst" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +#, fuzzy +msgid "Realm" +msgstr "gebied:" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Contactlijst" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "Adres" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Contactlijst" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Contactlijst" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Verbinden" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "afgebroken" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "voltooid" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "gemist" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1554,108 +1780,82 @@ msgstr "" "Status: %s\n" "Tijdsduur: %i mins %i secs\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Uitgaande oproep" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Gereed." -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Informatie" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Zoekt de lokatie van het telefoonnummer..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Kon dit nummer niet vinden." -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Slecht geformuleerd SIP-adres. Een SIP-adres ziet er uit als sip:" -"gebruikersnaam@domeinnaam" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Verbinden" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 #, fuzzy msgid "Could not call" msgstr "Kon niet oproepen" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 #, fuzzy msgid "is contacting you" msgstr "belt u." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Verbonden." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 #, fuzzy msgid "Call aborted" msgstr "afgebroken" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 #, fuzzy msgid "Could not pause the call" msgstr "Kon niet oproepen" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 #, fuzzy msgid "Pausing the current call..." msgstr "Kon niet oproepen" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Uw computer maakt schijnbaar gebruik van ALSA geluidsdrivers.\n" -"Dit is de beste keuze. Maar de pcm oss emulatie module mist\n" -"en linphone heeft deze nodig. Geeft u alstublieft het commando\n" -"'modprobe snd-pcm-oss' als root om de module te laden." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Uw computer maakt schijnbaar gebruik van ALSA geluidsdrivers.\n" -"Dit is de beste keuze. Maar de mixer oss emulatie module mist\n" -"en linphone heeft deze nodig. Geeft u alstublieft het commando\n" -"'modprobe snd-mixer-oss' als root om de module te laden." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "STUN adres wordt opgezocht..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1709,152 +1909,190 @@ msgid "Pending" msgstr "" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Informatie" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 #, fuzzy msgid "Remote ringing." msgstr "Externe diensten" -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 #, fuzzy msgid "Remote ringing..." msgstr "Externe diensten" -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Chat met %s" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 #, fuzzy msgid "Call resumed." msgstr "Oproep beeindigd" -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Oproepen of\n" "beantwoorden" -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Oproep beeindigd." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Gebruiker is bezet." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Gebruiker is tijdelijk niet beschikbaar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "De gebruiker wenst niet gestoord te worden." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Oproep geweigerd." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 #, fuzzy msgid "Redirected" msgstr "Doorgeschakeld naar %s..." -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 #, fuzzy msgid "Call failed." msgstr "Oproep geannuleerd." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Registratie op %s mislukt (time-out)." -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Authorisatie gegevens" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "U heeft %i oproep(en) gemist." msgstr[1] "U heeft %i oproep(en) gemist." +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "Slecht geformuleerd SIP-adres. Een SIP-adres ziet er uit als sip:" +#~ "gebruikersnaam@domeinnaam" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Uw computer maakt schijnbaar gebruik van ALSA geluidsdrivers.\n" +#~ "Dit is de beste keuze. Maar de pcm oss emulatie module mist\n" +#~ "en linphone heeft deze nodig. Geeft u alstublieft het commando\n" +#~ "'modprobe snd-pcm-oss' als root om de module te laden." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Uw computer maakt schijnbaar gebruik van ALSA geluidsdrivers.\n" +#~ "Dit is de beste keuze. Maar de mixer oss emulatie module mist\n" +#~ "en linphone heeft deze nodig. Geeft u alstublieft het commando\n" +#~ "'modprobe snd-mixer-oss' als root om de module te laden." + #~ msgid "Chat with %s" #~ msgstr "Chat met %s" @@ -1862,18 +2100,10 @@ msgstr[1] "U heeft %i oproep(en) gemist." #~ msgid "Choosing a username" #~ msgstr "gebruikersnaam:" -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Informatie" - #, fuzzy #~ msgid "Enable video" #~ msgstr "Aan" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Authorisatie gegevens" - #, fuzzy #~ msgid "Unmute" #~ msgstr "Ongelimiteerd" @@ -1923,10 +2153,6 @@ msgstr[1] "U heeft %i oproep(en) gemist." #~ "gebruikt linphone altijd IPv4. Wijzig uw configuratie wanneer u IPv6 wilt " #~ "gebruiken." -#, fuzzy -#~ msgid "Incoming call from %s" -#~ msgstr "Inkomende oproep" - #, fuzzy #~ msgid "_Modes" #~ msgstr "Codecs" @@ -2004,10 +2230,6 @@ msgstr[1] "U heeft %i oproep(en) gemist." #~ msgid "Closed" #~ msgstr "Gesloten" -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Adres" - #, fuzzy #~ msgid "_View" #~ msgstr "Video" @@ -2250,9 +2472,6 @@ msgstr[1] "U heeft %i oproep(en) gemist." #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "Het wordt sterk aangeraden om poort 5060 te gebruiken." -#~ msgid "SIP port" -#~ msgstr "SIP-poort" - #~ msgid "@" #~ msgstr "@" @@ -2296,9 +2515,6 @@ msgstr[1] "U heeft %i oproep(en) gemist." #~ msgid "None." #~ msgstr "Geen." -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Proxy/registratieserver registratieveld" - #~ msgid "Send registration:" #~ msgstr "Verstruur registratie:" @@ -2326,9 +2542,6 @@ msgstr[1] "U heeft %i oproep(en) gemist." #~ msgid "userid:" #~ msgstr "gebruikersID:" -#~ msgid "realm:" -#~ msgstr "gebied:" - #~ msgid "Text:" #~ msgstr "Tekst:" @@ -2386,9 +2599,6 @@ msgstr[1] "U heeft %i oproep(en) gemist." #~ msgid "Index" #~ msgstr "Index" -#~ msgid "Server address" -#~ msgstr "Serveradres" - #~ msgid "28k modem" #~ msgstr "28k modem" diff --git a/po/pl.po b/po/pl.po index 869f9b85e..fbcbdbd6d 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2003-08-22 12:50+0200\n" "Last-Translator: Robert Nasiadek \n" "Language-Team: Polski \n" @@ -15,12 +15,12 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "" @@ -94,46 +94,51 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Informacja" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -142,242 +147,243 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1023 +#: ../gtk/main.c:1227 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 #, fuzzy msgid "Call ended" msgstr "Rozmowa odrzucona." -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "linia" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Dzwonie do " -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 #, fuzzy msgid "Add to addressbook" msgstr "Książka adresowa" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 #, fuzzy msgid "Presence status" msgstr "Obecność" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nazwa" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "Połączenie odwołane." -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "(Brak informacji kontaktowych !)" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, c-format msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Jakość (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Min przepustowość (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parametr" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Włączone" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Wyłączone" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 #, fuzzy msgid "None" msgstr "Brak." -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -439,110 +445,118 @@ msgstr "" msgid "I have already a sip account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 #, fuzzy msgid "Username:" msgstr "Podręcznik" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 #, fuzzy msgid "Password:" msgstr "Twoje hasło:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "Podręcznik" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "Twoje hasło:" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "Podręcznik" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "Twoje hasło:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "" -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "" @@ -611,138 +625,153 @@ msgstr "Połączenie odwołane." msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 #, fuzzy msgid "Calling..." msgstr "Dzwonie do " -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 #, fuzzy msgid "Incoming call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 #, fuzzy msgid "In call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 #, fuzzy msgid "Paused call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 #, fuzzy msgid "Call ended." msgstr "Rozmowa odrzucona." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Połączenie odwołane." -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -792,99 +821,99 @@ msgid "_Options" msgstr "" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Informacja" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "Enable self-view" msgstr "Włączone" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 #, fuzzy msgid "SIP address or phone number:" msgstr "Adres serwera rejestracji sip" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 #, fuzzy msgid "Contacts" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -#, fuzzy -msgid "Add" -msgstr "Adres" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Add contacts from directory" msgstr "Informacje o kodeku" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contact" msgstr "(Brak informacji kontaktowych !)" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "Dzwonie do " -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "My current identity:" msgstr "Tożsamość" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Podręcznik" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Twoje hasło:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + #: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" @@ -947,6 +976,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -984,10 +1014,6 @@ msgstr "Informacje o kodeku" msgid "Please enter the domain password" msgstr "" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "" @@ -1027,326 +1053,394 @@ msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "" - -#: ../gtk/sip_account.ui.h:8 #, fuzzy msgid "Registration duration (sec):" msgstr "Rejestracja powiodła się." +#: ../gtk/sip_account.ui.h:8 +msgid "Contact params (optional):" +msgstr "" + #: ../gtk/sip_account.ui.h:9 -msgid "Register" +msgid "Route (optional):" msgstr "" #: ../gtk/sip_account.ui.h:10 #, fuzzy +msgid "Transport" +msgstr "Dzwonie do " + +#: ../gtk/sip_account.ui.h:11 +msgid "Register" +msgstr "" + +#: ../gtk/sip_account.ui.h:12 +#, fuzzy msgid "Publish presence information" msgstr "Informacje o kodeku" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "" #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" +msgid "anonymous" msgstr "" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" +msgid "GSSAPI" msgstr "" #: ../gtk/parameters.ui.h:3 -msgid "default camera" +msgid "SASL" msgstr "" #: ../gtk/parameters.ui.h:4 -msgid "CIF" +msgid "default soundcard" msgstr "" #: ../gtk/parameters.ui.h:5 +msgid "a sound card" +msgstr "" + +#: ../gtk/parameters.ui.h:6 +msgid "default camera" +msgstr "" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "" + +#: ../gtk/parameters.ui.h:8 #, fuzzy msgid "Audio codecs" msgstr "Kodeki audio" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 #, fuzzy msgid "Video codecs" msgstr "Kodeki audio" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 #, fuzzy msgid "Transport" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 -msgid "Network protocol and ports" -msgstr "" - #: ../gtk/parameters.ui.h:24 -msgid "Direct connection to the Internet" +msgid "Tunnel" msgstr "" #: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +msgid "DSCP fields" msgstr "" #: ../gtk/parameters.ui.h:26 #, fuzzy -msgid "Public IP address:" -msgstr "Adres sip:" +msgid "SIP/TCP port" +msgstr "Port SIP" #: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" +#, fuzzy +msgid "SIP/UDP port" +msgstr "Port SIP" #: ../gtk/parameters.ui.h:28 -msgid "Behind NAT / Firewall (use ICE)" +msgid "Network protocol and ports" msgstr "" #: ../gtk/parameters.ui.h:29 -msgid "Behind NAT / Firewall (use uPnP)" +msgid "Direct connection to the Internet" msgstr "" #: ../gtk/parameters.ui.h:30 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:33 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:34 +#, fuzzy +msgid "Public IP address:" +msgstr "Adres sip:" + +#: ../gtk/parameters.ui.h:35 #, fuzzy msgid "Stun server:" msgstr "Dźwięk" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 #, fuzzy msgid "NAT and Firewall" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 #, fuzzy msgid "Network settings" msgstr "Sieć" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 #, fuzzy msgid "Ring sound:" msgstr "Źródło nagrywania:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 #, fuzzy msgid "Capture device:" msgstr "Użyj tego urządzenia dźwięku:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 #, fuzzy msgid "Ring device:" msgstr "Użyj tego urządzenia dźwięku:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 #, fuzzy msgid "Playback device:" msgstr "Użyj tego urządzenia dźwięku:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 #, fuzzy msgid "Audio" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 #, fuzzy msgid "Video input device:" msgstr "Dźwięk" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Dźwięk" + +#: ../gtk/parameters.ui.h:48 #, fuzzy msgid "Video" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 #, fuzzy msgid "Your username:" msgstr "Podręcznik" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 #, fuzzy msgid "Your resulting SIP address:" msgstr "Twój adres sip:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 #, fuzzy msgid "Default identity" msgstr "Tożsamość" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +#, fuzzy +msgid "Add" +msgstr "Adres" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 #, fuzzy msgid "Proxy accounts" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 #, fuzzy msgid "Privacy" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Włączony" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Wyłącz" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 #, fuzzy msgid "Codecs" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 #, fuzzy msgid "Codecs" msgstr "Kodeki" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 #, fuzzy msgid "Language" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 #, fuzzy msgid "Level" msgstr "Dzwonie do " -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 #, fuzzy msgid "User interface" msgstr "Podręcznik" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Adres serwera:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Informacje o kodeku" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Dzwonie do " + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 #, fuzzy msgid "Done" msgstr "Brak." @@ -1376,7 +1470,7 @@ msgstr "" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Sieć" #: ../gtk/dscp_settings.ui.h:2 @@ -1431,6 +1525,14 @@ msgid "Round trip time" msgstr "Właściwości dźwięku" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Informacje o kodeku" @@ -1515,19 +1617,141 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Sieć" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "Brak informacji" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Dzwonie do " + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Dzwonie do " + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "Adres" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Dzwonie do " + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Dzwonie do " + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Lącze" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1537,107 +1761,82 @@ msgid "" "Duration: %i mn %i sec\n" msgstr "" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 #, fuzzy msgid "Ready" msgstr "Gotowy." -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Informacja" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "" -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "" -#: ../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:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 #, fuzzy msgid "Contacting" msgstr "Dzwonie do " -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 #, fuzzy msgid "Could not call" msgstr "Nie można znaleźć pixmapy: %s" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 #, fuzzy msgid "is contacting you" msgstr "dzwoni do Ciebie." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Połączony" -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 #, fuzzy msgid "Call aborted" msgstr "Połączenie odwołane." -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Używasz sterowników ALSA do dźwięku.\n" -"To jest najlepszy wybór. Jednak brakuje modułu emulacji pcm oss,\n" -"a Linphone go wymaga. Uruchom 'modprobe snd-pcm-oss' jako root,\n" -"aby go załadować" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Używasz sterowników ALSA do dźwięku.\n" -"To jest najlepszy wybór. Jednak brakuje modułu emulacji mixera oss,\n" -"a Linphone go wymaga. Uruchom 'modprobe snd-mixer-oss' jako root,\n" -"aby go załadować" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1690,146 +1889,155 @@ msgid "Pending" msgstr "" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Informacja" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 #, fuzzy msgid "Remote ringing." msgstr "Rejestruje..." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 #, fuzzy msgid "Remote ringing..." msgstr "Rejestruje..." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 #, fuzzy msgid "Call resumed." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Zadzwoń lub\n" "Odpowiedz" -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 #, fuzzy msgid "Call terminated." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Osoba jest zajęta." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Osoba jest tymczasowo niedostępna." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "Osoba nie chce, aby jej przeszkadzać." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 #, fuzzy msgid "Call failed." msgstr "Połączenie odwołane." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Rejestracja powiodła się." -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Informacje o kodeku" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1837,17 +2045,37 @@ msgstr[0] "" msgstr[1] "" #, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Informacja" +#~ 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 " + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Używasz sterowników ALSA do dźwięku.\n" +#~ "To jest najlepszy wybór. Jednak brakuje modułu emulacji pcm oss,\n" +#~ "a Linphone go wymaga. Uruchom 'modprobe snd-pcm-oss' jako root,\n" +#~ "aby go załadować" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Używasz sterowników ALSA do dźwięku.\n" +#~ "To jest najlepszy wybór. Jednak brakuje modułu emulacji mixera oss,\n" +#~ "a Linphone go wymaga. Uruchom 'modprobe snd-mixer-oss' jako root,\n" +#~ "aby go załadować" #, fuzzy #~ msgid "Enable video" #~ msgstr "Włączone" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Informacje o kodeku" - #, fuzzy #~ msgid "Contact list" #~ msgstr "Dzwonie do " @@ -1913,10 +2141,6 @@ msgstr[1] "" #~ msgid "Gone" #~ msgstr "Brak." -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Adres" - #, fuzzy #~ msgid "Display filters" #~ msgstr "Wyświetlana nazwa:" @@ -2021,9 +2245,6 @@ msgstr[1] "" #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "Rekomendowane jest użycie portu 5060." -#~ msgid "SIP port" -#~ msgstr "Port SIP" - #~ msgid "@" #~ msgstr "@" @@ -2084,10 +2305,6 @@ msgstr[1] "" #~ msgid "Index" #~ msgstr "Indeks" -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Adres serwera:" - #~ msgid "28k modem" #~ msgstr "Modem 28K" diff --git a/po/pt_BR.po b/po/pt_BR.po index 1ebd70a43..de51d73d7 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2006-07-11 23:30+0200\n" "Last-Translator: Rafael Caesar Lenzi \n" "Language-Team: pt_BR \n" @@ -17,12 +17,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:969 #, fuzzy, c-format msgid "Call %s" msgstr "Histórico de chamadas" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "" @@ -97,46 +97,51 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Informações" + +#: ../gtk/main.c:573 #, fuzzy, c-format msgid "Call with %s" msgstr "Bate-papo com %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -145,242 +150,243 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1023 +#: ../gtk/main.c:1227 #, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "Linphone - Histórico de chamadas" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 #, fuzzy msgid "Call ended" msgstr "Chamada cancelada." -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "linha" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "Abortado" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Contatando " -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 #, fuzzy msgid "Add to addressbook" msgstr "Catálogo de endereços" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Status de presença" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "Histórico de chamadas" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 #, fuzzy msgid "Chat" msgstr "Sala de bate-papo" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Edicar informação de contato" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, c-format msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Taxa (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Bitrate mínimo (kbits/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parâmetros" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Ativado" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Desativado" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 #, fuzzy msgid "Account" msgstr "Aceitar" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "Nenhum" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -442,110 +448,118 @@ msgstr "" msgid "I have already a sip account and I just want to use it" msgstr "" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 #, fuzzy msgid "Username:" msgstr "Usuário" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 #, fuzzy msgid "Password:" msgstr "Senha:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "Usuário" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "Senha:" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "Usuário" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "Senha:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "" -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +msgid "SIP account configuration assistant" +msgstr "" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "" @@ -615,138 +629,153 @@ msgstr "Histórico de chamadas" msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 #, fuzzy msgid "Calling..." msgstr "Contatando " -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 #, fuzzy msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 #, fuzzy msgid "In call" msgstr "Contatando " -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 #, fuzzy msgid "Paused call" msgstr "Contatando " -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 #, fuzzy msgid "Call ended." msgstr "Chamada cancelada." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Histórico de chamadas" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Camadas recebidas" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -796,99 +825,99 @@ msgid "_Options" msgstr "" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Configuração de proxy/registrador" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "Enable self-view" msgstr "Ativado" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 #, fuzzy msgid "Contacts" msgstr "Contatando " -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -#, fuzzy -msgid "Add" -msgstr "Endereço" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Editar" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Add contacts from directory" msgstr "Informação de contato" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contact" msgstr "Edicar informação de contato" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "Camadas recebidas" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 #, fuzzy msgid "My current identity:" msgstr "Identificação SIP:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 #, fuzzy msgid "Username" msgstr "Usuário" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 #, fuzzy msgid "Password" msgstr "Senha:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 #, fuzzy msgid "Automatically log me in" msgstr "Adquirir automaticamente um nome de servidor válido." +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + #: ../gtk/main.ui.h:39 #, fuzzy msgid "Login information" @@ -950,6 +979,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -987,10 +1017,6 @@ msgstr "Autenticação requerida" msgid "Please enter the domain password" msgstr "" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - #: ../gtk/call_logs.ui.h:1 #, fuzzy msgid "Call history" @@ -1032,326 +1058,395 @@ msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Rota (opcional):" - -#: ../gtk/sip_account.ui.h:8 #, fuzzy msgid "Registration duration (sec):" msgstr "Período do registo:" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Rota (opcional):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Rota (opcional):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Contatando " + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 #, fuzzy msgid "Publish presence information" msgstr "Informar informação de presença" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "" #: ../gtk/parameters.ui.h:1 -msgid "default soundcard" +msgid "anonymous" msgstr "" #: ../gtk/parameters.ui.h:2 -msgid "a sound card" +msgid "GSSAPI" msgstr "" #: ../gtk/parameters.ui.h:3 -msgid "default camera" +msgid "SASL" msgstr "" #: ../gtk/parameters.ui.h:4 -msgid "CIF" +msgid "default soundcard" msgstr "" #: ../gtk/parameters.ui.h:5 +msgid "a sound card" +msgstr "" + +#: ../gtk/parameters.ui.h:6 +msgid "default camera" +msgstr "" + +#: ../gtk/parameters.ui.h:7 +msgid "CIF" +msgstr "" + +#: ../gtk/parameters.ui.h:8 #, fuzzy msgid "Audio codecs" msgstr "Codec's de áudio" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 #, fuzzy msgid "Video codecs" msgstr "Codec's de áudio" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 #, fuzzy msgid "Transport" msgstr "Contatando " -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 -msgid "Network protocol and ports" -msgstr "" - #: ../gtk/parameters.ui.h:24 -msgid "Direct connection to the Internet" +msgid "Tunnel" msgstr "" #: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +msgid "DSCP fields" msgstr "" #: ../gtk/parameters.ui.h:26 #, fuzzy -msgid "Public IP address:" -msgstr "Endereço sip:" +msgid "SIP/TCP port" +msgstr "Porta SIP" #: ../gtk/parameters.ui.h:27 -msgid "Behind NAT / Firewall (use STUN to resolve)" -msgstr "" +#, fuzzy +msgid "SIP/UDP port" +msgstr "Porta SIP" #: ../gtk/parameters.ui.h:28 -msgid "Behind NAT / Firewall (use ICE)" +msgid "Network protocol and ports" msgstr "" #: ../gtk/parameters.ui.h:29 -msgid "Behind NAT / Firewall (use uPnP)" +msgid "Direct connection to the Internet" msgstr "" #: ../gtk/parameters.ui.h:30 +msgid "Behind NAT / Firewall (specify gateway IP )" +msgstr "" + +#: ../gtk/parameters.ui.h:31 +msgid "Behind NAT / Firewall (use STUN to resolve)" +msgstr "" + +#: ../gtk/parameters.ui.h:32 +msgid "Behind NAT / Firewall (use ICE)" +msgstr "" + +#: ../gtk/parameters.ui.h:33 +msgid "Behind NAT / Firewall (use uPnP)" +msgstr "" + +#: ../gtk/parameters.ui.h:34 +#, fuzzy +msgid "Public IP address:" +msgstr "Endereço sip:" + +#: ../gtk/parameters.ui.h:35 #, fuzzy msgid "Stun server:" msgstr "Dispositivo de som" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 #, fuzzy msgid "NAT and Firewall" msgstr "Contatando " -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 #, fuzzy msgid "Network settings" msgstr "Rede" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 #, fuzzy msgid "Ring sound:" msgstr "Som do toque:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 #, fuzzy msgid "Capture device:" msgstr "Dispositivo de captura de som:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 #, fuzzy msgid "Ring device:" msgstr "Dispositivo de som" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 #, fuzzy msgid "Playback device:" msgstr "Dispositivo de som:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 #, fuzzy msgid "Audio" msgstr "Contatando " -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 #, fuzzy msgid "Video input device:" msgstr "Dispositivo de som" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Dispositivo de som" + +#: ../gtk/parameters.ui.h:48 #, fuzzy msgid "Video" msgstr "Contatando " -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 #, fuzzy msgid "Your username:" msgstr "Usuário" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 #, fuzzy msgid "Your resulting SIP address:" msgstr "Seu endereço SIP:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 #, fuzzy msgid "Default identity" msgstr "Identificação SIP:" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +#, fuzzy +msgid "Add" +msgstr "Endereço" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Editar" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Remover" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 #, fuzzy msgid "Proxy accounts" msgstr "Contatando " -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 #, fuzzy msgid "Privacy" msgstr "Contatando " -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Ativado" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Desativar" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 #, fuzzy msgid "Codecs" msgstr "Contatando " -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 #, fuzzy msgid "Codecs" msgstr "Codec's de áudio" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 #, fuzzy msgid "Language" msgstr "Contatando " -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 #, fuzzy msgid "Level" msgstr "Contatando " -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 #, fuzzy msgid "User interface" msgstr "Usuário" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Endereço do servidor" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Informações de autenticação" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Contatando " + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 #, fuzzy msgid "Done" msgstr "Nenhum" @@ -1380,7 +1475,7 @@ msgstr "" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Rede" #: ../gtk/dscp_settings.ui.h:2 @@ -1436,6 +1531,14 @@ msgid "Round trip time" msgstr "Propriedades de som" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +msgid "Video resolution sent" +msgstr "" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Informação de contato" @@ -1520,19 +1623,141 @@ msgstr "" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Rede" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "Informações não disponíveis" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Contatando " + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Contatando " + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "Endereço" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Contatando " + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Contatando " + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Contatando " + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "Abortado" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "Competado" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "Perdido" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, fuzzy, c-format msgid "" "%s at %s\n" @@ -1546,98 +1771,82 @@ msgstr "" "Status: %s\n" "Duração: %i min %i seg\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Chamadas efetuadas" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 #, fuzzy msgid "Ready" msgstr "Pronto." -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Informações" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Procurando por telefone de destino..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Não foi possível encontrar este número." -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 #, fuzzy msgid "Contacting" msgstr "Contatando " -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 #, fuzzy msgid "Could not call" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 #, fuzzy msgid "is contacting you" msgstr "está chamado você." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Conectado." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 #, fuzzy msgid "Call aborted" msgstr "Abortado" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "" -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1688,146 +1897,155 @@ msgid "Pending" msgstr "" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Informações" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 #, fuzzy msgid "Remote ringing." msgstr "Serviços remotos" -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 #, fuzzy msgid "Remote ringing..." msgstr "Serviços remotos" -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Bate-papo com %s" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 #, fuzzy msgid "Call resumed." msgstr "Chamada cancelada." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Ligar ou\n" "atender" -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "" -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Usuário está ocupado." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Usuário está temporáriamente indisponível." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "" -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "" -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "" -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 #, fuzzy msgid "Redirected" msgstr "Redirecionado para %s..." -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 #, fuzzy msgid "Call failed." msgstr "Histórico de chamadas" -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Registro em %s efetuado." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Registro em %s efetuado." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Registro falhou (tempo esgotado)." -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Informações de autenticação" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1841,18 +2059,10 @@ msgstr[1] "Você perdeu %i ligação(ões)." #~ msgid "Choosing a username" #~ msgstr "Usuário" -#, fuzzy -#~ msgid "Confirmation" -#~ msgstr "Informações" - #, fuzzy #~ msgid "Enable video" #~ msgstr "Ativado" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Informações de autenticação" - #, fuzzy #~ msgid "Contact list" #~ msgstr "Contatando " @@ -1894,10 +2104,6 @@ msgstr[1] "Você perdeu %i ligação(ões)." #~ "linphone sempre usa IPv4. Por favor atualize sua configuração se deseja " #~ "usar IPv6" -#, fuzzy -#~ msgid "Incoming call from %s" -#~ msgstr "Camadas recebidas" - #~ msgid "Accept" #~ msgstr "Aceitar" @@ -1928,10 +2134,6 @@ msgstr[1] "Você perdeu %i ligação(ões)." #~ msgid "Gone" #~ msgstr "Nenhum" -#, fuzzy -#~ msgid "SIP address" -#~ msgstr "Endereço" - #, fuzzy #~ msgid "_Properties" #~ msgstr "Propriedades RTP:" @@ -2064,9 +2266,6 @@ msgstr[1] "Você perdeu %i ligação(ões)." #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "É altamente recomendavel usar a porta 5060." -#~ msgid "SIP port" -#~ msgstr "Porta SIP" - #~ msgid "Identity" #~ msgstr "Identificação" @@ -2092,9 +2291,6 @@ msgstr[1] "Você perdeu %i ligação(ões)." #~ msgid "None." #~ msgstr "Nenhum" -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Configuração de proxy/registrador" - #~ msgid "Send registration:" #~ msgstr "Enviar registro:" @@ -2128,9 +2324,6 @@ msgstr[1] "Você perdeu %i ligação(ões)." #~ msgid "Index" #~ msgstr "Índice" -#~ msgid "Server address" -#~ msgstr "Endereço do servidor" - #~ msgid "28k modem" #~ msgstr "Modem 28k" diff --git a/po/ru.po b/po/ru.po index 0c81d472b..cd4da5d08 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2010-01-22 18:43+0300\n" "Last-Translator: Maxim Prokopyev \n" "Language-Team: Russian \n" @@ -17,12 +17,12 @@ 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:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "Набрать %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Послать текст к %s" @@ -105,37 +105,37 @@ msgstr "Я" msgid "Couldn't find pixmap file: %s" msgstr "Невозможно найти графический файл: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "Неверный sip-контакт!" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "" "Вывод некоторой отладочной информации на устройство стандартного вывода во " "время работы" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "путь к файлу для записи журнала работы." -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "Запускать только в системном лотке, не показывая главное окно" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "адрес для звонка" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "автоматически принимать входящие вызовы, если включено" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -143,12 +143,17 @@ msgstr "" "Укажите рабочий каталог (должен содержать установленные файлы приложения, " "например: c:\\Program Files\\Linphone)" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Подтверждение" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Чат с %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -161,68 +166,68 @@ msgstr "" "его(её) в свой контактный лист?\n" "Если вы ответите Нет, этот человек будет временно заблокирован." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Пожалуйста, введите пароль для пользователя %s\n" " в домене %s:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 msgid "Call error" msgstr "Ошибка вызова" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Разговор окончен" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Входящий вызов" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Ответить" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Отклонить" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 msgid "Call paused" msgstr "Вызов приостановлен" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Порты" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Ссылка на сайт" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - видео-телефон для интернета" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (По умолчанию)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "Мы переведены на %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -230,172 +235,173 @@ msgstr "" "На этом компьютере не обнаружено ни одной звуковой карты.\n" "Вы не сможете совершать или принимать аудио-вызовы." -#: ../gtk/main.c:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "Свободный SIP видео-телефон" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "Добавить в адресную книгу" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Статус присутствия" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Имя" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 msgid "Call" msgstr "Вызов" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 #, fuzzy msgid "Chat" msgstr "Комната чата" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Поиск в директории %s" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Редактировать контакт '%s'" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Удалить контакт '%s'" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Удалить контакт '%s'" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Добавить новый контакт из директории '%s'" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Частота (Гц)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Статус" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Минимальный битрейт (кбит/с)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Параметры" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Включен" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Отключен" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Учетная запись" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "Английский" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Французский" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Шведский" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Итальянский" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Испанский" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "Бразильский португальский" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Польский" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Немецкий" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Русский" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "Японский" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Нидерландский" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Венгерский" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Чешский" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "Китайский" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "Традиционный китайский" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "Норвежский" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Вы должны перезапустить Linphone для того, чтобы языковые настройки вступили " "в силу." -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "Нет" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "ZRTP" @@ -461,59 +467,63 @@ msgstr "" msgid "I have already a sip account and I just want to use it" msgstr "У меня уже есть учётная запись SIP и я хочу использовать её" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "Введите ваше имя пользователя на linphone.org" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Имя пользователя:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Пароль:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "Введите информацию о вашей учётной записи" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 msgid "Username*" msgstr "Имя пользователя*" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 msgid "Password*" msgstr "Пароль*" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "Домен*" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "Прокси" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "(*) Обязательные поля" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 msgid "Username: (*)" msgstr "Имя пользователя: (*)" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 msgid "Password: (*)" msgstr "Пароль: (*)" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "Email: (*)" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "Подтвердите ваш пароль: (*)" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." @@ -522,11 +532,11 @@ msgstr "" "сервер недоступен.\n" "Вернитесь и попробуйте ещё раз." -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Спасибо! Учетная запись успешно настроена и готова к использованию." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" @@ -536,35 +546,40 @@ msgstr "" "только что выслали вам на электронную почту.\n" "Затем вернитесь и нажмите на кнопку Далее." -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Помощник настройки учётной записи" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Добро пожаловать в помощник настройки учётной записи" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Помощник настройки учётной записи" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 msgid "Configure your account (step 1/1)" msgstr "Настройте свою учётную запись (шаг 1/1)" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "Введите ваше имя пользователя SIP (шаг 1/1)" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "Введи информация об учётной записи (шаг 1/2)" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "Проверка (шаг 2/2)" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "Ошибка" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "Завершение" @@ -636,135 +651,150 @@ msgstr "ICE фильтр" msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, fuzzy, c-format msgid "%.3f seconds" msgstr "%i секунда" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "Вызов..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "Входящий вызов" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "хорошее" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "среднее" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "плохое" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "очень плохое" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "слишком плохое" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "недоступно" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "Защищено SRTP" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Защищено ZRTP - [токен: %s]" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "Не проверен" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Проверен" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "В конференции" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "Соединен с" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "Приостановленный вызов" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Звонок закончен." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 #, fuzzy msgid "Transfer done." msgstr "Перевести" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Перевести" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "Продолжить" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Пауза" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, fuzzy msgid "(Paused)" msgstr "Пауза" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Введите информацию для входа %s" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Входящий звонок от %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Имя вызываемого абонента" @@ -811,89 +841,90 @@ msgid "_Options" msgstr "_Настройки" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Прокси/Регистратор конфигуратор" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Включить своё видео" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "_Помощь" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "Показать окно отладки" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "_Домашняя страница" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "Проверить _Обновления" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 msgid "Account assistant" msgstr "Помощник настройки учётной записи" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "SIP-адрес или номер телефона:" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "Совершить новый вызов" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "Контакты" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Добавить" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Редактировать" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Поиск" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "Добавить контакты из директории" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "Добавить контакт" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Recent calls" msgstr "Недавние вызовы" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Мой текущий идентификатор:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Имя пользователя" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Пароль" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Интернет-соединение:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Входить автоматически" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "UserID" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Информация для входа" @@ -940,6 +971,7 @@ msgstr "" "Видео-телефон для интернета, использующий стандартный протокол SIP (rfc3261)." #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -952,6 +984,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -997,10 +1030,6 @@ msgstr "Linphone - Необходима аутентификация" msgid "Please enter the domain password" msgstr "Введите пароль" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "UserID" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "История звонков" @@ -1038,274 +1067,320 @@ msgid "Looks like sip:" msgstr "Похоже на sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Маршрут (необязательно):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Продолжительность регистрации (сек):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Маршрут (необязательно):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Маршрут (необязательно):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Транспорт" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "Зарегистрироваться" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Опубликовывать статус присутствия" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "Настроить учётную запись SIP" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "звуковая карта по умолчанию" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "звуковая карта" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "камера по умолчаию" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Аудио кодеки" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Видео кодеки" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "C" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "SIP (UDP)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "SIP (TCP)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "SIP (TLS)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Настройки" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Установить MTU:" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "Отправлять DTFM как SIP Info" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "Использовать IPv6 вместо IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Транспорт" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "Тип шифрования потока" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "Видео RTP/UDP:" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "Аудио RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "Туннель" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 #, fuzzy msgid "Media encryption is mandatory" msgstr "Тип шифрования потока" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "Туннель" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:26 +#, fuzzy +msgid "SIP/TCP port" +msgstr "SIP порт" + +#: ../gtk/parameters.ui.h:27 +#, fuzzy +msgid "SIP/UDP port" +msgstr "SIP порт" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "Протокол и порты" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Прямое подключение к Интернету" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "За NAT / брандмауэром (укажите IP-адрес шлюза ниже)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Внешний IP-адрес:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "За NAT / брандмауэром (использовать STUN)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 #, fuzzy msgid "Behind NAT / Firewall (use ICE)" msgstr "За NAT / брандмауэром (использовать STUN)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "За NAT / брандмауэром (использовать STUN)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Внешний IP-адрес:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "Сервер STUN:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT и брандмауэр" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Настройки сети" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Звук звонка:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "Специальное устройство ALSA (необязательно):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Устройство захвата:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Устройство звонка:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Устройство воспроизведения:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Включить подавление эхо" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Звук" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Устройство захвата видео:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Предпочтительное разрешение видео:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Устройство захвата видео:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Видео" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Настройки мультимедиа" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" "Эта секция устанавливает ваш SIP-адрес, когда вы не используете SIP-аккаунт" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Отображаемое имя (напр.: Иван Сидоров):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Имя пользователя:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Результирующий SIP-адрес:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Идентификатор по умолчанию" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "Мастер" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Добавить" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Редактировать" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Удалить" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Учетные записи прокси" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Стереть все пароли" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Конфеденциальность" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "Управление учётными записями SIP" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Включить" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Выключить" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Кодеки" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 означает \"безлимитный\"" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Ограничение исходящего потока в кбит/сек:" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Ограничение скорости входящего потока в кбит/сек" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "Включить адаптивный контроль скорости" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1313,31 +1388,54 @@ msgstr "" "Адаптивное управление скоростью - это техника, позволяющая динамически " "определять доступную пропускную способность сети во время звонка." -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Управление скоростью сети" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "Кодеки" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Язык" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Показывать расширенные настройки" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "Уровень" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Интерфейс пользователя" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Server-Adresse:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Ошибка аутентификации" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "метка" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Учетные записи прокси" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Готово" @@ -1363,7 +1461,7 @@ msgstr "Подождите" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Настройки" #: ../gtk/dscp_settings.ui.h:2 @@ -1423,6 +1521,15 @@ msgid "Round trip time" msgstr "Настройки звука" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Предпочтительное разрешение видео:" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Контактная информация" @@ -1508,19 +1615,142 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Настройки" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "недоступно" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Кодеки" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +#, fuzzy +msgid "Realm" +msgstr "Название:" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Звук" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "SIP-адрес" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Найти кого-нибудь" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Разное" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Подключение..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "отмененный" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "завершённый" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "пропущенный" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1535,105 +1765,77 @@ msgstr "" "Статус: %s\n" "Длительность: %i мин %i сек\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Исходящий звонок" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Готов" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Подтверждение" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Поиск адреса для телефонного номера..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Не могу найти этот номер." -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Не могу опознать sip адрес. SIP-URL обычно выглядит как sip:" -"username@domainname" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Соединение" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "Не удалось позвонить" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Извините, мы превысили максимальное количество одновременных вызовов" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "пытается связаться с вами" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr " и ответил автоответчик." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "Изменение параметров вызова..." -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Соединён." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "Вызов отменён" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "Не удалось приостановить вызов" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "Приостановление текущего вызова..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Ваш компьютер использует звуковой драйвер ALSA.\n" -"Это лучший выбор. Однако, модуль эмуляции PCM OSS\n" -"не найден, а он нужен для linphone.\n" -"Пожалуйста, выполните от имени пользователя root команду 'modprobe snd-pcm-" -"oss', чтобы загрузить его." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Ваш компьютер использует звуковой драйвер ALSA.\n" -"Это лучший выбор. Однако, модуль микшера OSS\n" -"не найден, а он нужен для linphone.\n" -"Пожалуйста, выполните от имени пользователя root команду 'modprobe snd-pcm-" -"oss' чтобы загрузить его." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "Идет поиск Stun..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1682,10 +1884,15 @@ msgid "Pending" msgstr "В ожидании" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Продолжительность" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Неизвестная ошибка" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1693,7 +1900,7 @@ msgstr "" "Введеный адрес SIP-прокси является недействительным, он должен выглядеть как " "\"sip:имя_хоста\"" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1702,128 +1909,132 @@ msgstr "" "Они должны выглядеть как sip:username@proxydomain, например such as sip:" "alice@example.net" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "Невозможно зайти как %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "Абонент вызывается." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "Абонент вызывается..." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "Гудки." -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "Вызов %s приостановлен." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "Вызов отвечен %s - в ожидании." -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "Разговор продолжен." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "Вызов отвечен %s." -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "Несовместимо, проверьте кодеки..." -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 #, fuzzy msgid "We have been resumed." msgstr "Наш вызов продолжен..." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 #, fuzzy msgid "Call is updated by remote." msgstr "Вызов обновлён вызываемым абонентом..." -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Звонок прерван." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Пользователь занят." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Пользователь временно недоступен." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "Абонент не хочет отвечать." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Звонок отклонён." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "Нет ответа." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "Ошибка протокола." -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "Переадресован" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 #, fuzzy msgid "Incompatible media parameters." msgstr "Несовместимо, проверьте кодеки..." -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "Не удалось совершить вызов." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Регистрация на %s прошла успешно." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "Отмена регистрации на %s завершена." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "время ожидания истекло" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "Регистрация на %s не удалась: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, c-format msgid "Authentication token is %s" msgstr "Аутентификационный токен: %s" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1831,8 +2042,36 @@ msgstr[0] "У вас пропущен %i звонок." msgstr[1] "У вас пропущено %i звонка." msgstr[2] "У вас пропущено %i звонков." -#~ msgid "label" -#~ msgstr "метка" +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "Не могу опознать sip адрес. SIP-URL обычно выглядит как sip:" +#~ "username@domainname" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Ваш компьютер использует звуковой драйвер ALSA.\n" +#~ "Это лучший выбор. Однако, модуль эмуляции PCM OSS\n" +#~ "не найден, а он нужен для linphone.\n" +#~ "Пожалуйста, выполните от имени пользователя root команду 'modprobe snd-" +#~ "pcm-oss', чтобы загрузить его." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Ваш компьютер использует звуковой драйвер ALSA.\n" +#~ "Это лучший выбор. Однако, модуль микшера OSS\n" +#~ "не найден, а он нужен для linphone.\n" +#~ "Пожалуйста, выполните от имени пользователя root команду 'modprobe snd-" +#~ "pcm-oss' чтобы загрузить его." #~ msgid "by %s" #~ msgstr "со стороны: %s" @@ -1871,9 +2110,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "No common codecs" #~ msgstr "Нет общих кодеков" -#~ msgid "Authentication failure" -#~ msgstr "Ошибка аутентификации" - #~ msgid "Please choose a username:" #~ msgstr "Выберите имя пользователя:" @@ -1898,9 +2134,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "Verifying" #~ msgstr "Проверка" -#~ msgid "Confirmation" -#~ msgstr "Подтверждение" - #~ msgid "Creating your account" #~ msgstr "Создание аккаунта" @@ -2038,9 +2271,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ "Ваш компьютер подключен по IPv6. Linphone по умолчанию использует IPv4. " #~ "Пожалуйста, обновите настройки если хотите использовать IPv6." -#~ msgid "Incoming call from %s" -#~ msgstr "Входящий звонок от %s" - #~ msgid "Assistant" #~ msgstr "Помощник" @@ -2153,9 +2383,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "gtk-find" #~ msgstr "Найти" -#~ msgid "SIP address" -#~ msgstr "SIP-адрес" - #~ msgid "_View" #~ msgstr "_Вид" @@ -2187,9 +2414,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "Use the supplied stun server above and do as best as possible" #~ msgstr "Использовать доступный Stun сервер и делать так хорошо как возможно" -#~ msgid "Miscelaneous" -#~ msgstr "Разное" - #~ msgid "Go" #~ msgstr "Старт" @@ -2416,9 +2640,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "It is strongly recommended to use port 5060." #~ msgstr "Рекомендуется использовать порт 5060." -#~ msgid "SIP port" -#~ msgstr "SIP порт" - #~ msgid "@" #~ msgstr "@" @@ -2466,9 +2687,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "None." #~ msgstr "Нет." -#~ msgid "Proxy/Registrar configuration box" -#~ msgstr "Прокси/Регистратор конфигуратор" - #~ msgid "Send registration:" #~ msgstr "Отправить регистрацию:" @@ -2496,9 +2714,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "userid:" #~ msgstr "ID пользователя:" -#~ msgid "realm:" -#~ msgstr "Название:" - #~ msgid "Linphone - Call history" #~ msgstr "Linphone - История звонков" @@ -2560,10 +2775,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "Firewall 's external ip address (in dot notations):" #~ msgstr "IP-Adresse des Firewall (in Punktnotation)" -#, fuzzy -#~ msgid "Server address" -#~ msgstr "Server-Adresse:" - #~ msgid "28k modem" #~ msgstr "28K Modem" diff --git a/po/sr.po b/po/sr.po index d0b470f95..46e362a45 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2013-02-11 19:03+0200\n" "Last-Translator: Мирослав Николић \n" "Language-Team: Serbian \n" @@ -16,12 +16,12 @@ 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:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "Позови „%s“" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Пошаљи текст за %s" @@ -106,35 +106,35 @@ msgstr "Ја" msgid "Couldn't find pixmap file: %s" msgstr "Не могу да пронађем датотеку сличице: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "Неисправан сип контакт !" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "бележи у стандардни излаз неке податке за уклањање грешака док ради." -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "путања до датотеке за уписивање бележака." -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "Покреће се само у системској фиоци, не приказује главно сучеље." -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "адреса за позивање управо сада" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "ако је подешено сам ће се јављати на долазне позиве" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -142,12 +142,17 @@ msgstr "" "Наводи радни директоријум (треба да буде основа инсталације, нпр: c:" "\\Program Files\\Linphone)" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Потврђујем" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Позив са корисником %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -160,68 +165,68 @@ msgstr "" "на ваш списак пријатеља ?\n" "Ако одговорите са не, ова особа ће привремено бити стављена на црни списак." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Унесите вашу лозинку за корисничко име %s\n" " на домену %s:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 msgid "Call error" msgstr "Грешка позива" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Позив је завршен" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Долазни позив" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Јави се" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Одбиј" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 msgid "Call paused" msgstr "Позив је заустављен" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Кодеци" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Веза веб сајта" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Линфон — интернет телефон са снимком" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (основно)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "Преселили смо се на %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -229,170 +234,171 @@ msgstr "" "Ниједна звучна картица није откривен ана овом рачунару.\n" "Нећете бити у могућности да шаљете или да примате звучне позиве." -#: ../gtk/main.c:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "Слободан СИП телефон са снимком" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "Додајте у адресар" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Стање присуства" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Име" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 msgid "Call" msgstr "Позови" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Тражи у директоријуму „%s“" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Уредите контакт „%s“" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Обришите контакт „%s“" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Обришите контакт „%s“" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Додајте нови контакт из директоријума „%s“" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Проток (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Стање" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Најмањи проток бита (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Параметри" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "Укључено" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Искључено" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Налог" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "Енглески" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Француски" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Шведски" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Италијански" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Шпански" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "Бразилски португалски" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Пољски" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Немачки" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Руски" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "Јапански" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Холандски" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Мађарски" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Чешки" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "Кинески" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "Традиционални кинески" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "Норвешки" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Трба поново да покренете линфон да би нови изабрани језик ступио на снагу." -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "Ништа" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "СРТП" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "ЗРТП" @@ -461,109 +467,118 @@ msgstr "Већ имам један налог и желим да га корис msgid "I have already a sip account and I just want to use it" msgstr "Већ имам један налог и желим да га користим" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Корисничко име:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Лозинка:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "Корисничко име" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "Лозинка" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "Корисничко име:" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "Лозинка:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Хвала вам. Ваш налог је сада подешен и спреман за употребу." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Помоћник подешавања налога" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Добродошли у помоћника подешавања налога" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Помоћник подешавања налога" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Подесите СИП налог" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "" @@ -635,135 +650,150 @@ msgstr "Позив није успео." msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, fuzzy, c-format msgid "%.3f seconds" msgstr "%i секунда" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "Позивам..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "Долазни позив" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "добро" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "просечно" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "оскудно" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "јадно" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "много лоше" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "недоступно" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "Осигурано СРТП-ом" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Осигурано ЗРТП-ом [потврђивање идентитета: %s]" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "Непроверено подешавање" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Проверено подешавање" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "На конференцији" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "У позиву" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "Заустављен позив" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Позив је завршен." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 #, fuzzy msgid "Transfer done." msgstr "Пребаци" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Пребаци" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "Настави" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Застани" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, fuzzy msgid "(Paused)" msgstr "Застани" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Унесите податке пријављивања за %s" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Име позивника" @@ -810,90 +840,91 @@ msgid "_Options" msgstr "_Могућности" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Потврђујем" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Укључи самовиђење" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "По_моћ" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "Прикажи прозорче прочишћавања" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "_Матична страница" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "Провери _ажурирања" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "Account assistant" msgstr "Помоћник подешавања налога" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "СИП адреса или број телефона:" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "Започните нови позив" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "Пријатељи" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Додај" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Уреди" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Тражи" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "Додај пријатеље из директоријума" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "Додај пријатеља" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 msgid "Recent calls" msgstr "Скорашњи позиви" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Мој тренутни идентитет:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Корисничко име" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Лозинка" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Интернет веза:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Сам ме пријави" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "ИБ корисника" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Подаци пријављивања" @@ -940,6 +971,7 @@ msgstr "" "Интернет телефон са снимком који користи уобичајени СИП (rfc3261) протокол." #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -952,6 +984,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -997,10 +1030,6 @@ msgstr "Линфон — Потребно је потврђивање идент msgid "Please enter the domain password" msgstr "Унесите лозинку домена" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "ИБ корисника" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Историјат позива" @@ -1038,273 +1067,317 @@ msgid "Looks like sip:" msgstr "Изгледа као „sip:<назив посредника>" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Рута (изборно):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Трајање уписа (сек):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Рута (изборно):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Рута (изборно):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Пренос" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "Упиши се" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Објави податке о присуству" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "Подесите СИП налог" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "основна звучна картица" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "звучна картица" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "основна камера" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "ЦИФ" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "Звучни кодеци" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "Кодеци снимка" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "В" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "СИП (УДП)" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "СИП (ТЦП)" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "СИП (ТЛС)" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Подешавања" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Подеси јединицу највећег преноса:" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "Пошаљи ДТМФ као СИП податке" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "Користи ИПв6 уместо ИПв4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Пренос" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "Врста шифровања медија" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "РТП/УДП снимка:" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "РТП/УДП звука:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 #, fuzzy msgid "Media encryption is mandatory" msgstr "Врста шифровања медија" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:26 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:27 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "Мрежни протокол и прикључници" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Непосредна веза на Интернет" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "Иза НАТ-а / мрежне баријере (испод наведите ИП мрежног пролаза)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Јавна ИП адреса:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Иза НАТ-а / мрежне баријере (користите СТУН за решавање)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 #, fuzzy msgid "Behind NAT / Firewall (use ICE)" msgstr "Иза НАТ-а / мрежне баријере (користите СТУН за решавање)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "Иза НАТ-а / мрежне баријере (користите СТУН за решавање)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Јавна ИП адреса:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "Стун сервер:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "НАТ и мрежна баријера" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Подешавања мреже" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Звук звона:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "АЛСА-ин посебни уређај (изборно):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Уређај за снимање:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Уређај за звоно:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Уређај за пуштање:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Укључи поништавање одјека" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Звук" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Улазни уређај снимка:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Жељена резолуција снимка:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Улазни уређај снимка:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Снимак" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Подешавања мултимедија" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "Овај одељак одређује вашу СИП адресу када не користите СИП налог" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Ваше приказано име (нпр: Пера Перић):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Ваше корисничко име:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Ваша резултирајућа СИП адреса:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Основни идентитет" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Додај" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Уреди" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Уклони" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Посреднички налози" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Обриши све лозинке" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Приватност" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "Управљај СИП налозима" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Укључи" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Искључи" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Кодеци" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 значи „неограничено“" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Ограничење брзине слања у Kb/s:" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Ограничење брзине преузимања у Kb/s:" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "Укључи прилагодљиво управљање протоком" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." @@ -1312,31 +1385,54 @@ msgstr "" "Прилагодљиво управљање протоком је техника за променљиво погађање " "доступног пропусног опсега за време позива." -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Управљање пропусним опсегом" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "Kодеци" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Језик" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Прикажи напредна подешавања" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "Ниво" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Корисничко сучеље" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "Адреса СИП посредника:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Потврђивање идентитета није успело" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "натпис" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Посреднички налози" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Готово" @@ -1362,7 +1458,7 @@ msgstr "Молим сачекајте" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Подешавања" #: ../gtk/dscp_settings.ui.h:2 @@ -1418,6 +1514,15 @@ msgid "Round trip time" msgstr "" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Жељена резолуција снимка:" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Подаци о пријатељу" @@ -1503,19 +1608,141 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Подешавања" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +#, fuzzy +msgid "Not yet available" +msgstr "недоступно" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Кодеци" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Звук" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "СИП адреса или број телефона:" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Потражите неког" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Снимак" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Повезујем се..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "прекинути" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "завршени" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "пропуштени" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1530,103 +1757,77 @@ msgstr "" "Стање: %s\n" "Трајање: %i мин %i сек\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Одлазни позив" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Спреман" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Потврђујем" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Тражим одредиште телефонског броја..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Не могу да решим овај број." -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Не могу да обрадим дату сип адресу. Сип адреса обично изгледа као „sip:" -"корисник@домен“" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Ступам у везу" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "Не могу да позовем" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Извините, достигли смо највећи број истовремених позива" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "вам се обраћа" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr " и затражени само-одговор." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "Мењам параметре позива..." -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Повезан сам." -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "Позив је прекинут" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "Не могу да зауставим позив" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "Заустављам тренутни позив..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Изгледа да ваш рачунар користи АЛСА управљачке програме за звук.\n" -"То је најбољи избор. Међутим недостаје пцм осс модул\n" -"за емулацију а потребан је линфону. Молим извршите\n" -"„modprobe snd-pcm-oss“ као администратор да га учитате." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Изгледа да ваш рачунар користи АЛСА управљачке програме за звук.\n" -"То је најбољи избор. Међутим недостаје миксер осс модул\n" -"за емулацију а потребан је линфону. Молим извршите\n" -"„modprobe snd-mixer-oss“ као администратор да га учитате." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "У току је тражење стуна..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1675,10 +1876,15 @@ msgid "Pending" msgstr "На чекању" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Трајање" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Непозната грешка" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1686,7 +1892,7 @@ msgstr "" "Адреса сип посредника коју сте унели је неисправна, мора почети на „sip:“ за " "којим следи назив домаћина." -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1695,126 +1901,130 @@ msgstr "" "Треба да изгледа као „sip:корисник@домен-посредника, као што је „sip:" "alice@example.net“" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "Не могу да се пријавим као %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "Удаљено звоњење." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "Удаљено звоњење..." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "Ранији медиј." -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "Позив са „%s“ је заустављен." -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "Позив на који је одговорио „%s“ — на чекању." -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "Позив је настављен." -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "На позив је одговорио „%s“." -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 #, fuzzy msgid "We have been resumed." msgstr "Позив нам је настављен..." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 #, fuzzy msgid "Call is updated by remote." msgstr "Позив је ажуриран удаљеним..." -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Позив је завршен." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Корисник је заузет." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Корисник је привремено недоступан." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "Корисник не жели да буде узнемираван." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Позив је одбијен." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "Нема одговора." -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "Грешка у протоколу." -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "Преусмерен" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "Позив није успео." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Уписивање на „%s“ је успело." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "Исписивање са „%s“ је обављено." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "нема ограничења одговора" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "Уписивање на „%s“ није успело: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, c-format msgid "Authentication token is %s" msgstr "Симбол потврђивања идентитета је „%s“" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -1823,8 +2033,34 @@ msgstr[1] "Пропустили сте %i позива." msgstr[2] "Пропустили сте %i позива." msgstr[3] "Пропустили сте један позив." -#~ msgid "label" -#~ msgstr "натпис" +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "Не могу да обрадим дату сип адресу. Сип адреса обично изгледа као „sip:" +#~ "корисник@домен“" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Изгледа да ваш рачунар користи АЛСА управљачке програме за звук.\n" +#~ "То је најбољи избор. Међутим недостаје пцм осс модул\n" +#~ "за емулацију а потребан је линфону. Молим извршите\n" +#~ "„modprobe snd-pcm-oss“ као администратор да га учитате." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Изгледа да ваш рачунар користи АЛСА управљачке програме за звук.\n" +#~ "То је најбољи избор. Међутим недостаје миксер осс модул\n" +#~ "за емулацију а потребан је линфону. Молим извршите\n" +#~ "„modprobe snd-mixer-oss“ као администратор да га учитате." #~ msgid "Chat with %s" #~ msgstr "Ћаскајте са „%s“" @@ -1856,9 +2092,6 @@ msgstr[3] "Пропустили сте један позив." #~ msgid "Verifying" #~ msgstr "Проверавам" -#~ msgid "Confirmation" -#~ msgstr "Потврђујем" - #~ msgid "Creating your account" #~ msgstr "Правим ваш налог" @@ -1892,6 +2125,3 @@ msgstr[3] "Пропустили сте један позив." #~ msgid "No common codecs" #~ msgstr "Нема познатих кодека" - -#~ msgid "Authentication failure" -#~ msgstr "Потврђивање идентитета није успело" diff --git a/po/sv.po b/po/sv.po index c814f86c4..7d5421323 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2009-02-17 15:22+0100\n" "Last-Translator: Emmanuel Frécon \n" "Language-Team: SWEDISH \n" @@ -16,12 +16,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:969 #, c-format msgid "Call %s" msgstr "Ringer %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "Skicka text till %s" @@ -97,35 +97,35 @@ msgstr "Mikrofon av" msgid "Couldn't find pixmap file: %s" msgstr "Kunde inte hitta pixmap filen: %s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "ogiltig SIP kontakt!" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "skriv loggning information under körning" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "Starta ikonifierat, visa inte huvudfönstret" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "Samtalsmottagare" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "Om på, besvara automatisk alla inkommande samtal" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -133,12 +133,17 @@ msgstr "" "Välj en arbetskatalog som ska vara basen för installationen, såsom C:" "\\Program\\Linphone" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "Bekräftelse" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "Samtal med %s" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -151,239 +156,240 @@ msgstr "" "henne till din kontaktlista?\n" "Om du svarar nej, personen kommer att vara bannlyst." -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "Mata in ditt lösenord för användaren %s\n" "vid domänen %s:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "Samtalshistorik" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "Samtalet slut" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Avböj" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "avbrytade" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "Portar" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "Webbsajt" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - en video Internet telefon" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 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:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "Närvarostatus" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Namn" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "Ringer %s" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "Sök i %s katalogen" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "Ändra kontakt '%s'" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "Ta bort kontakt '%s'" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Ta bort kontakt '%s'" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "Lägg till kontakt ifrån %s katalogen" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "Frekvens (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "Min. datahastighet (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "Parametrar" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "På" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "Av" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "Engelska" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "Fransk" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "Svenska" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "Italiensk" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "Spanska" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "Portugisiska" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "Polska" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "Tyska" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "Ryska" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "Japanska" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "Nederländksa" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "Hungerska" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "Tjekiska" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "Kinesiska" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 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:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -450,109 +456,118 @@ msgstr "Jag har redan ett konto och vill bara använda det." msgid "I have already a sip account and I just want to use it" msgstr "Jag har redan ett konto och vill bara använda det." -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "Användarnamn:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "Lösenord:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "Användarnamn" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "Lösenord" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "Användarnamn:" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "Lösenord:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "Tack. Ditt konto är nu konfigurerad och färdig att användas." -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "Kontoinstallationsassistenten" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "Välkommen till kontoinstallationsassistenten" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "Kontoinstallationsassistenten" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Konfigurera ett SIP konto" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 #, fuzzy msgid "Terminating" msgstr "Lägg på" @@ -623,136 +638,151 @@ msgstr "Samtalet avböjdes." msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 #, fuzzy msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 #, fuzzy msgid "In call" msgstr "I samtal med" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 #, fuzzy msgid "Paused call" msgstr "Lägg på" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "Samtalet slut." -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "Samtalet avböjdes." -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "Mata in ditt lösenord för domänen %s:" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "Inkommande samtal från %s" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -799,96 +829,97 @@ msgid "_Options" msgstr "" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "Bekräftelse" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "Själv bild" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 #, fuzzy msgid "Show debug window" msgstr "Linphone debug fönster" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "_Homepage" msgstr "Hemsidan" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Check _Updates" msgstr "Letar efter uppdateringar" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "Account assistant" msgstr "Kontoinstallationsassistenten" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "Användarnamn" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 #, fuzzy msgid "Contacts" msgstr "Kontaktar" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "Lägg till" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "Editera" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "Sök" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "Lägg till kontakt ifrån katalogen" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contact" msgstr "Hittat kontakt %i" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "I samtal" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "Min nuvarande identitet" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Användarnamn" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Lösenord" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "Internet förbindelse:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "Logga mig automatiskt" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "AnvändarID" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "Login information" @@ -953,6 +984,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" #: ../gtk/contact.ui.h:2 @@ -988,10 +1020,6 @@ msgstr "Linphone - Autentisering krävs" msgid "Please enter the domain password" msgstr "Mata in lösenordet för domänen" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "AnvändarID" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "Samtalshistorik" @@ -1030,310 +1058,377 @@ msgid "Looks like sip:" msgstr "" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "Route (tillval):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "Registreringsfrekvens (sek.):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "Route (tillval):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "Route (tillval):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "Transport" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "Publicera närvaro information" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "Konfigurera ett SIP konto" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "default ljudkort" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 #, fuzzy msgid "a sound card" msgstr "ett ljud kort\n" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "default kamera" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 #, fuzzy msgid "Audio codecs" msgstr "" "Audio codecs\n" "Video codecs" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 #, fuzzy msgid "Video codecs" msgstr "" "Audio codecs\n" "Video codecs" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 msgid "SIP (UDP)" msgstr "" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 msgid "SIP (TCP)" msgstr "" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 msgid "SIP (TLS)" msgstr "" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "Inställningar" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "Välj MTU (Maximum Transmission Unit):" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "Kicka DTMF koder som SIP info" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "Använd IPv6 istället av IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "Transport" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:26 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:27 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "Direkt förbindelse till Internet" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "Bakom en NAT / brandvägg (specificera gatewap IP adress nedan)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "Publik IP adress:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "Bakom en NAT / brandvägg (använd STUN för att avgöra adressen)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 #, fuzzy msgid "Behind NAT / Firewall (use ICE)" msgstr "Bakom en NAT / brandvägg (använd STUN för att avgöra adressen)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "Bakom en NAT / brandvägg (använd STUN för att avgöra adressen)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "Publik IP adress:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "STUN server:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT och Brandvägg" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "Nätverksinställningar" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "Ring signal:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "ALSA speciell enhet (tillval):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "Mikrofon enhet:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "Ringning enhet:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "Uppspelningsenhet:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "Tillåta ekokancellering" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "Audio" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "Video ingångsenhet:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "Video upplösning:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "Video ingångsenhet:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "Video" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "Multimedia inställningar" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "" "Denna sektion specificerar din SIP adress när du inte använder ett SIP konto" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "Ditt synliga namn, e.g. Kalle Karlsson:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "Ditt användarnamn:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "Din SIP adress:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "Default identitet" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "Lägg till" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "Editera" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "Ta bort" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "Proxy konton" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "Glöm alla lösenord" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "Integritet" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "Hantera SIP konton" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "Möjliggör" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "Inaktivera" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 står för \"utan begränsning\"" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "Max upstream bandbreddshastighet i kbit/sek:" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "Max downstream bandbreddshastighet i kbit/sek:" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "Bandbreddskontroll" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "Codecs" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "Språk" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "Visa avancerade inställningar" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "Nivå" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "Användarinterface" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "SIP Adress" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Linphone - Autentisering krävs" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "etikett" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "Proxy konton" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "Klar" @@ -1359,7 +1454,7 @@ msgstr "Vänta" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "Inställningar" #: ../gtk/dscp_settings.ui.h:2 @@ -1418,6 +1513,15 @@ msgid "Round trip time" msgstr "" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "Video upplösning:" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "Kontakt information" @@ -1503,19 +1607,140 @@ msgstr "" msgid "1" msgstr "" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "Inställningar" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "Codecs" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "Audio" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "SIP Adress" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "Sök efter kontakter" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "Video" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "Kontaktar" + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "avbrytade" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "avslutade" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "missade" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1530,108 +1755,82 @@ msgstr "" "Status: %s\n" "Längd: %i min %i sek\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "Utgående samtal" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "Redo" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "Bekräftelse" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "Leta efter telefonnummer för destinationen..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "Kan inte nå dett nummer." -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"Kan inte förstå angiven SIP adress. En SIP adress vanligen ser ut som sip:" -"användare@domänen" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "Kontaktar" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 #, fuzzy msgid "Could not call" msgstr "Kunde inte ringa" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 #, fuzzy msgid "is contacting you" msgstr "kontaktar dig." -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "Kopplad" -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 #, fuzzy msgid "Call aborted" msgstr "avbrytade" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 #, fuzzy msgid "Could not pause the call" msgstr "Kunde inte ringa" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 #, fuzzy msgid "Pausing the current call..." msgstr "Nuvarande samtal" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"Din dator verkar använda ALSA drivrutiner för ljud.\n" -"Detta är det bästa valet. Dock PCM OSS emuleringsmodulen\n" -"saknas och linphone behöver ha det. Var god exekvera\n" -"'modprobe snd-pcm-oss' som root för att ladda in den." - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"Din dator verkar använda ALSA drivrutiner för ljud.\n" -"Detta är det bästa valet. Dock OSS mixer emuleringsmodulen\n" -"saknas och linphone behöver ha det. Var god exekvera\n" -"'modprobe snd-mixer-oss' som root för att ladda in den." - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "STUN uppslagning pågår..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1680,10 +1879,15 @@ msgid "Pending" msgstr "Pågående" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "Förlopp" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "Okänd bug" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1691,7 +1895,7 @@ msgstr "" "SIP proxy adressen som du matade in är inte rätt, adressen måste starta med " "\"sip:\", följd av ett hostnamn" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1699,137 +1903,167 @@ 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:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "Kunde inte logga in som %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 #, fuzzy msgid "Remote ringing..." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "Tidig media" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Samtal med %s" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 #, fuzzy msgid "Call resumed." msgstr "Samtalet slut" -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "Samtalet slut." -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "Användare upptagen." -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "Användaren temporärt inte tillgänglig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "Användaren vill inte bli störd." -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 #, fuzzy msgid "No response." msgstr "Inget svar inom angiven tid" -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 #, fuzzy msgid "Redirected" msgstr "Omdirigerat till %s..." -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 #, fuzzy msgid "Call failed." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lyckades." -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lyckades." -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "Inget svar inom angiven tid" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislyckades: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Linphone - Autentisering krävs" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, 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 "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "Kan inte förstå angiven SIP adress. En SIP adress vanligen ser ut som sip:" +#~ "användare@domänen" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "Din dator verkar använda ALSA drivrutiner för ljud.\n" +#~ "Detta är det bästa valet. Dock PCM OSS emuleringsmodulen\n" +#~ "saknas och linphone behöver ha det. Var god exekvera\n" +#~ "'modprobe snd-pcm-oss' som root för att ladda in den." + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "Din dator verkar använda ALSA drivrutiner för ljud.\n" +#~ "Detta är det bästa valet. Dock OSS mixer emuleringsmodulen\n" +#~ "saknas och linphone behöver ha det. Var god exekvera\n" +#~ "'modprobe snd-mixer-oss' som root för att ladda in den." #~ msgid "Chat with %s" #~ msgstr "Chatta med %s" @@ -1858,9 +2092,6 @@ msgstr[1] "Du har %i missade samtal" #~ msgid "Verifying" #~ msgstr "Verifierar" -#~ msgid "Confirmation" -#~ msgstr "Bekräftelse" - #~ msgid "Creating your account" #~ msgstr "Skapar ditt konto" @@ -1887,10 +2118,6 @@ msgstr[1] "Du har %i missade samtal" #~ "Registrera hos FONICS\n" #~ "virtuella nätverk!" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Linphone - Autentisering krävs" - #~ msgid "Unmute" #~ msgstr "Mikrofon på" @@ -2115,9 +2342,6 @@ msgstr[1] "Du har %i missade samtal" #~ "Din dator verkar vara kopplad till ett IPv6 nätverk. Default, använder " #~ "linphone IPv4. Uppdatera din konfiguration om du vill använda IPv6." -#~ msgid "Incoming call from %s" -#~ msgstr "Inkommande samtal från %s" - #~ msgid "Assistant" #~ msgstr "Assistent" @@ -2214,9 +2438,6 @@ msgstr[1] "Du har %i missade samtal" #~ msgid "Unknown" #~ msgstr "Okänd" -#~ msgid "SIP address" -#~ msgstr "SIP Adress" - #~ msgid "Bresilian" #~ msgstr "Brasiliansk" diff --git a/po/zh_CN.po b/po/zh_CN.po index 0d21351a8..f55f87dfd 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2011-01-08 23:51+0800\n" "Last-Translator: Aron Xu \n" "Language-Team: Chinese (simplified) \n" @@ -18,12 +18,12 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "呼叫 %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "发送消息给 %s" @@ -97,46 +97,51 @@ msgstr "静音" msgid "Couldn't find pixmap file: %s" msgstr "无法打开位图文件:%s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "无效的 SIP 联系人!" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "运行时向标准输出记录调试信息。" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "启动到系统托盘,不显示主界面。" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "现在呼叫的地址" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "是否设置呼叫自动应答" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "指定工作目录(应为安装目录例如 C:\\Program Files\\Linphone)" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "确认" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "与 %s 通话" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -148,68 +153,68 @@ msgstr "" "您是否允许他看到您的在线状态或者将它加为您的联系人允许?\n" "如果您回答否,则会将该人临时性的放入黑名单" -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "请输入 %s@%s 的密码:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "呼叫历史" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "呼叫结束" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "呼入" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "拒绝" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "中断" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "端口" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "网站" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - 互联网视频电话" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (默认)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -217,170 +222,171 @@ msgstr "" "未在此计算机上检测到声卡。\n" "您无法发送或接收音频呼叫。" -#: ../gtk/main.c:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "免费的 SIP 视频电话" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "在线状态" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名称" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "呼叫 %s" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "在 %s 目录中查找 " -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "编辑联系人 %s" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "删除联系人 %s" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "删除联系人 %s" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "从 %s 目录增加联系人 " -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "采样率(Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "状态" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "最小比特率(kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "参数" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "启用" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "禁用" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "帐户" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "英语" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "法语" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "瑞典语" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "意大利语" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "西班牙语" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "巴西葡萄牙语" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "波兰语" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "德语" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "俄语" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "日语" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "荷兰语" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "匈牙利语" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "捷克语" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "中文" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重启 linphone 以使语言选择生效。" -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -446,109 +452,118 @@ msgstr "我已经有一个帐户,并想使用原来的帐户" msgid "I have already a sip account and I just want to use it" msgstr "我已经有一个帐户,并想使用原来的帐户" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "用户名:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "密码:" -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "用户名" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "密码" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "用户名:" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "密码:" -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "谢谢,您的帐户已经配置完毕,可以使用。" -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "帐户设置向导" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "欢迎使用帐户设置向导" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "帐户设置向导" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "配置 SIP 帐户" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 #, fuzzy msgid "Terminating" msgstr "终止呼叫" @@ -620,136 +635,151 @@ msgstr "ICE 过滤器" msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "正在呼叫..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 #, fuzzy msgid "Incoming call" msgstr "呼入" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 #, fuzzy msgid "In call" msgstr "正在呼叫" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 #, fuzzy msgid "Paused call" msgstr "正在呼叫" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "通话结束。" -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "呼叫失败。" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 msgid "(Paused)" msgstr "" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "请输入 %s 的登录信息" +#: ../gtk/config-fetching.c:57 +#, fuzzy, c-format +msgid "fetching from %s" +msgstr "来自 %s 的呼叫" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -796,95 +826,96 @@ msgid "_Options" msgstr "" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "确认" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "启用自视" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 #, fuzzy msgid "Show debug window" msgstr "Linphone 调试窗口" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "_Homepage" msgstr "主页" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 #, fuzzy msgid "Check _Updates" msgstr "检查更新" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "Account assistant" msgstr "帐户设置向导" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "SIP 地址或电话号码:" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "联系人" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "添加" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "编辑" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "搜索" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "从目录增加联系人" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 #, fuzzy msgid "Add contact" msgstr "找到 %i 联系方式" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "呼入" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "当前地址:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "用户名" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "密码" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "网络连接:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "自动登录" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "用户 ID" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "登录信息" @@ -936,6 +967,7 @@ msgid "An internet video phone using the standard SIP (rfc3261) protocol." msgstr "一个采用标准 SIP (rfc3261) 协议的互联网视频电话" #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -948,6 +980,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -995,10 +1028,6 @@ msgstr "Linphone - 需要认证" msgid "Please enter the domain password" msgstr "请输入密码" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "用户 ID" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "呼叫历史" @@ -1037,312 +1066,379 @@ msgid "Looks like sip:" msgstr "类似于 sip:<代理主机名>" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "路由(可选):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "注册间隔(秒):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "路由(可选):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "路由(可选):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "传输协议" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "发布在线状态" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "配置 SIP 帐户" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "默认声卡" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 #, fuzzy msgid "a sound card" msgstr "声卡\n" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "默认摄像头" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 #, fuzzy msgid "Audio codecs" msgstr "" "音频编解码器\n" "视频编解码器" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 #, fuzzy msgid "Video codecs" msgstr "" "音频编解码器\n" "视频编解码器" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "C" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 #, fuzzy msgid "SIP (UDP)" msgstr "SIP (UDP):" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 #, fuzzy msgid "SIP (TCP)" msgstr "SIP (UDP):" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 #, fuzzy msgid "SIP (TLS)" msgstr "SIP (UDP):" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "设置" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "设置最大传输单元(MTU):" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "以 SIP 消息发送 DTMF" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "使用 IPv6 而非 IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "传输协议" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "视频 RTP/UDP:" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "音频 RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:26 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:27 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "直接连接到互联网" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "在 NAT 或防火墙后(填写网关 IP)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "公网 IP 地址:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "在 NAT 或防火墙后(使用 STUN 解决)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 #, fuzzy msgid "Behind NAT / Firewall (use ICE)" msgstr "在 NAT 或防火墙后(使用 STUN 解决)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "在 NAT 或防火墙后(使用 STUN 解决)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "公网 IP 地址:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "Stun 服务器:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT 及防火墙" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "网络设置" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "铃声文件:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "ALSA 特殊设备(可选):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "录音设备:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "响铃设备:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "回放设备:" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "启用回声抑制" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "音频" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "视频输入设备:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "视频分辨率:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "视频输入设备:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "视频" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "音视频设置" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "该段在您不使用SIP帐户时的SIP地址" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "您的显示名:" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "您的用户名:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "您的 SIP 地址结果:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "默认帐户" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "添加" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "编辑" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "移除" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "代理帐户" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "清除所有密码" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "隐私" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "SIP 帐户管理" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "启用" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "禁用" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "编解码器" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 表示 “没有限制”" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "上传速率限制 kbit/s:" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "下载速率限制 kbit/s:" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "带宽控制" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "编解码器" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "语言" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "显示高级设置" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "级别" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "用户界面" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "SIP 代理地址:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "Linphone - 需要认证" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "标签" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "代理帐户" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "完成" @@ -1368,7 +1464,7 @@ msgstr "请稍候" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "设置" #: ../gtk/dscp_settings.ui.h:2 @@ -1429,6 +1525,15 @@ msgid "Round trip time" msgstr "" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "视频分辨率:" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "联系人信息" @@ -1514,19 +1619,140 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "设置" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "编解码器" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "音频" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "SIP 地址或电话号码:" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "找人" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "视频" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "正在连接..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "中断" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "完成" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "丢失" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1541,104 +1767,80 @@ msgstr "" "状态:%s\n" "状态:%i 分 %i 秒\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "呼出" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "就绪" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "确认" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "查询电话号码目的地..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "该号码无法解析。" -#: ../coreapi/linphonecore.c:2252 -msgid "" -"Could not parse given sip address. A sip url usually looks like sip:" -"user@domain" -msgstr "" -"无法解析给定的 SIP 地址,SIP 地址应有如下格式:\n" -"sip:用户名@域名" - -#: ../coreapi/linphonecore.c:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "联系中" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 #, fuzzy msgid "Could not call" msgstr "无法呼叫" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "正在联系您" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr " 并询问了自动回答。" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "已连接。" -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 #, fuzzy msgid "Call aborted" msgstr "中断" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 #, fuzzy msgid "Could not pause the call" msgstr "无法呼叫" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"您的计算机正使用 ALSA 声音驱动。\n" -"ALSA 是最佳选择,然而 Linphone 必须的 PCM OSS 模拟模块缺失。\n" -"请以 root 用户运行 modprobe snd-pcm-oss 载入它。" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"您的计算机正使用 ALSA 声音驱动。\n" -"ALSA 是最佳选择,然而 Linphone 必须的 Mixer OSS 模拟模块缺失。\n" -"请以 root 用户运行 modprobe snd-mixer-oss 载入它。" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "正在进行 Stun 查找..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1687,16 +1889,21 @@ msgid "Pending" msgstr "挂起" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "通话时间" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "未知错误" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "您输入的 SIP 代理地址无效,它必须是以“sip:”开头,并紧随一个主机名。" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1704,133 +1911,161 @@ msgstr "" "您输入的地址无效。\n" "它应具有“sip:用户名@代理域”的形式,例如 sip:alice@example.net" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "无法登录为 %s" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "响铃。" -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 #, fuzzy msgid "Remote ringing..." msgstr "响铃。" -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "与 %s 通话" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 #, fuzzy msgid "Call resumed." msgstr "呼叫结束" -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "通话结束。" -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "被叫正忙。" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "您呼叫的用户暂时无法接通。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "用户已开启免打扰功能。" -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "呼叫被拒绝。" -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "没有响应。" -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "协议错误。" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "已重定向" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "呼叫失败。" -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "成功注册到 %s" -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "已在 %s 解除注册。" -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "没有响应,超时" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "注册到 %s 失败: %s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Linphone - 需要认证" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您错过了 %i 个呼叫。" -#~ msgid "label" -#~ msgstr "标签" +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "" +#~ "无法解析给定的 SIP 地址,SIP 地址应有如下格式:\n" +#~ "sip:用户名@域名" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "您的计算机正使用 ALSA 声音驱动。\n" +#~ "ALSA 是最佳选择,然而 Linphone 必须的 PCM OSS 模拟模块缺失。\n" +#~ "请以 root 用户运行 modprobe snd-pcm-oss 载入它。" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "您的计算机正使用 ALSA 声音驱动。\n" +#~ "ALSA 是最佳选择,然而 Linphone 必须的 Mixer OSS 模拟模块缺失。\n" +#~ "请以 root 用户运行 modprobe snd-mixer-oss 载入它。" #~ msgid "Keypad" #~ msgstr "数字键盘" @@ -1862,9 +2097,6 @@ msgstr[0] "您错过了 %i 个呼叫。" #~ msgid "Verifying" #~ msgstr "验证中" -#~ msgid "Confirmation" -#~ msgstr "确认" - #~ msgid "Creating your account" #~ msgstr "正在创建您的帐户" @@ -1894,10 +2126,6 @@ msgstr[0] "您错过了 %i 个呼叫。" #~ msgid "No common codecs" #~ msgstr "未找到常用编解码器" -#, fuzzy -#~ msgid "Authentication failure" -#~ msgstr "Linphone - 需要认证" - #~ msgid "Unmute" #~ msgstr "取消静音" @@ -2111,9 +2339,6 @@ msgstr[0] "您错过了 %i 个呼叫。" #~ msgid "Sound playback filter for MacOS X Core Audio drivers" #~ msgstr "MacOS X 核心声音驱动音频回放过滤器" -#~ msgid "Incoming call from %s" -#~ msgstr "来自 %s 的呼叫" - #~ msgid "Assistant" #~ msgstr "配置向导" diff --git a/po/zh_TW.po b/po/zh_TW.po index 26a086150..52db94544 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-24 14:04+0200\n" +"POT-Creation-Date: 2014-02-14 14:57+0100\n" "PO-Revision-Date: 2011-04-06 21:24+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: \n" @@ -17,12 +17,12 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:922 +#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 #, c-format msgid "Call %s" msgstr "播打給 %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:923 +#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 #, c-format msgid "Send text to %s" msgstr "傳送文字給 %s" @@ -96,47 +96,52 @@ msgstr "靜音" msgid "Couldn't find pixmap file: %s" msgstr "找不到 pixmap 檔:%s" -#: ../gtk/chat.c:336 ../gtk/friendlist.c:872 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 msgid "Invalid sip contact !" msgstr "無效的 sip 連絡人!" -#: ../gtk/main.c:92 +#: ../gtk/main.c:102 msgid "log to stdout some debug information while running." msgstr "執行時將一些除錯資訊記錄到標準輸出。" -#: ../gtk/main.c:99 +#: ../gtk/main.c:109 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:106 +#: ../gtk/main.c:116 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:113 +#: ../gtk/main.c:123 msgid "Start only in the system tray, do not show the main interface." msgstr "只在系統匣啟動,不要顯示主要介面。" -#: ../gtk/main.c:120 +#: ../gtk/main.c:130 msgid "address to call right now" msgstr "現在要打電話的位址" -#: ../gtk/main.c:127 +#: ../gtk/main.c:137 msgid "if set automatically answer incoming calls" msgstr "如啟用此項,將會自動接聽來電" -#: ../gtk/main.c:134 +#: ../gtk/main.c:144 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" "指定一個工作目錄(應該為安裝的根目錄,例如:c:\\Program Files\\Linphone)" -#: ../gtk/main.c:515 +#: ../gtk/main.c:151 +#, fuzzy +msgid "Configuration file" +msgstr "確認" + +#: ../gtk/main.c:573 #, c-format msgid "Call with %s" msgstr "和 %s 通話" -#: ../gtk/main.c:946 +#: ../gtk/main.c:1150 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -148,70 +153,70 @@ msgstr "" "您是否要允許他看見您的上線狀態或將他加入您的連絡人清單?\n" "如果您回答否,這個人會被暫時列入黑名單。" -#: ../gtk/main.c:1023 -#, c-format +#: ../gtk/main.c:1227 +#, fuzzy, c-format msgid "" "Please enter your password for username %s\n" -" at domain %s:" +" at realm %s:" msgstr "" "請輸入您使用者名稱 %s\n" "於網域 %s 的密碼:" -#: ../gtk/main.c:1126 +#: ../gtk/main.c:1339 #, fuzzy msgid "Call error" msgstr "通話紀錄" -#: ../gtk/main.c:1129 ../coreapi/linphonecore.c:3210 +#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 msgid "Call ended" msgstr "通話已結束" -#: ../gtk/main.c:1132 ../coreapi/linphonecore.c:240 +#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 msgid "Incoming call" msgstr "來電" -#: ../gtk/main.c:1134 ../gtk/incall_view.c:497 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 msgid "Answer" msgstr "接聽" -#: ../gtk/main.c:1136 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 msgid "Decline" msgstr "拒接" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy msgid "Call paused" msgstr "通話已放棄" -#: ../gtk/main.c:1142 +#: ../gtk/main.c:1355 #, fuzzy, c-format msgid "by %s" msgstr "連接埠" -#: ../gtk/main.c:1191 +#: ../gtk/main.c:1422 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1353 +#: ../gtk/main.c:1584 msgid "Website link" msgstr "網站連結" -#: ../gtk/main.c:1402 +#: ../gtk/main.c:1633 msgid "Linphone - a video internet phone" msgstr "Linphone - 網路視訊電話" -#: ../gtk/main.c:1494 +#: ../gtk/main.c:1725 #, c-format msgid "%s (Default)" msgstr "%s (預設值)" -#: ../gtk/main.c:1796 ../coreapi/callbacks.c:810 +#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 #, c-format msgid "We are transferred to %s" msgstr "我們被轉接到 %s" -#: ../gtk/main.c:1806 +#: ../gtk/main.c:2071 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -219,170 +224,171 @@ msgstr "" "在這臺電腦中偵測不到音效卡。\n" "您將無法傳送或接收語音電話。" -#: ../gtk/main.c:1911 +#: ../gtk/main.c:2207 msgid "A free SIP video-phone" msgstr "自由的 SIP 視訊電話" -#: ../gtk/friendlist.c:469 +#: ../gtk/friendlist.c:505 msgid "Add to addressbook" msgstr "" -#: ../gtk/friendlist.c:643 +#: ../gtk/friendlist.c:691 msgid "Presence status" msgstr "上線狀態" -#: ../gtk/friendlist.c:661 ../gtk/propertybox.c:367 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名稱" -#: ../gtk/friendlist.c:673 +#: ../gtk/friendlist.c:721 #, fuzzy msgid "Call" msgstr "播打給 %s" -#: ../gtk/friendlist.c:678 +#: ../gtk/friendlist.c:726 msgid "Chat" msgstr "" -#: ../gtk/friendlist.c:708 +#: ../gtk/friendlist.c:756 #, c-format msgid "Search in %s directory" msgstr "在 %s 目錄中搜尋" -#: ../gtk/friendlist.c:924 +#: ../gtk/friendlist.c:971 #, c-format msgid "Edit contact '%s'" msgstr "編輯連絡人「%s」" -#: ../gtk/friendlist.c:925 +#: ../gtk/friendlist.c:972 #, c-format msgid "Delete contact '%s'" msgstr "刪除連絡人「%s」" -#: ../gtk/friendlist.c:926 +#: ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "刪除連絡人「%s」" -#: ../gtk/friendlist.c:977 +#: ../gtk/friendlist.c:1024 #, c-format msgid "Add new contact from %s directory" msgstr "從 %s 目錄加入新的連絡人" -#: ../gtk/propertybox.c:373 +#: ../gtk/propertybox.c:562 msgid "Rate (Hz)" msgstr "頻率 (Hz)" -#: ../gtk/propertybox.c:379 +#: ../gtk/propertybox.c:568 msgid "Status" msgstr "狀態" -#: ../gtk/propertybox.c:385 -msgid "Min bitrate (kbit/s)" +#: ../gtk/propertybox.c:574 +#, fuzzy +msgid "Bitrate (kbit/s)" msgstr "最小頻寬 (kbit/s)" -#: ../gtk/propertybox.c:392 +#: ../gtk/propertybox.c:581 msgid "Parameters" msgstr "參數" -#: ../gtk/propertybox.c:435 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 msgid "Enabled" msgstr "已啟用" -#: ../gtk/propertybox.c:437 ../gtk/propertybox.c:578 +#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 msgid "Disabled" msgstr "已停用" -#: ../gtk/propertybox.c:624 +#: ../gtk/propertybox.c:813 msgid "Account" msgstr "帳號" -#: ../gtk/propertybox.c:764 +#: ../gtk/propertybox.c:1057 msgid "English" msgstr "英語" -#: ../gtk/propertybox.c:765 +#: ../gtk/propertybox.c:1058 msgid "French" msgstr "法語" -#: ../gtk/propertybox.c:766 +#: ../gtk/propertybox.c:1059 msgid "Swedish" msgstr "瑞典語" -#: ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:1060 msgid "Italian" msgstr "義大利語" -#: ../gtk/propertybox.c:768 +#: ../gtk/propertybox.c:1061 msgid "Spanish" msgstr "西班牙語" -#: ../gtk/propertybox.c:769 +#: ../gtk/propertybox.c:1062 msgid "Brazilian Portugese" msgstr "巴西葡萄牙語" -#: ../gtk/propertybox.c:770 +#: ../gtk/propertybox.c:1063 msgid "Polish" msgstr "波蘭語" -#: ../gtk/propertybox.c:771 +#: ../gtk/propertybox.c:1064 msgid "German" msgstr "德語" -#: ../gtk/propertybox.c:772 +#: ../gtk/propertybox.c:1065 msgid "Russian" msgstr "俄語" -#: ../gtk/propertybox.c:773 +#: ../gtk/propertybox.c:1066 msgid "Japanese" msgstr "日語" -#: ../gtk/propertybox.c:774 +#: ../gtk/propertybox.c:1067 msgid "Dutch" msgstr "荷蘭語" -#: ../gtk/propertybox.c:775 +#: ../gtk/propertybox.c:1068 msgid "Hungarian" msgstr "匈牙利語" -#: ../gtk/propertybox.c:776 +#: ../gtk/propertybox.c:1069 msgid "Czech" msgstr "捷克語" -#: ../gtk/propertybox.c:777 +#: ../gtk/propertybox.c:1070 msgid "Chinese" msgstr "中文" -#: ../gtk/propertybox.c:778 +#: ../gtk/propertybox.c:1071 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:779 +#: ../gtk/propertybox.c:1072 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:780 +#: ../gtk/propertybox.c:1073 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:781 +#: ../gtk/propertybox.c:1074 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:848 +#: ../gtk/propertybox.c:1141 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重新啟動 linphone 才能讓新選擇的語言生效。" -#: ../gtk/propertybox.c:934 +#: ../gtk/propertybox.c:1219 msgid "None" msgstr "" -#: ../gtk/propertybox.c:938 +#: ../gtk/propertybox.c:1223 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:944 +#: ../gtk/propertybox.c:1229 msgid "ZRTP" msgstr "" @@ -448,109 +454,118 @@ msgstr "我已經有帳號,並且要使用這個帳號" msgid "I have already a sip account and I just want to use it" msgstr "我已經有帳號,並且要使用這個帳號" -#: ../gtk/setupwizard.c:85 +#: ../gtk/setupwizard.c:46 +msgid "I want to specify a remote configuration URI" +msgstr "" + +#: ../gtk/setupwizard.c:89 msgid "Enter your linphone.org username" msgstr "" -#: ../gtk/setupwizard.c:92 +#: ../gtk/setupwizard.c:96 ../gtk/parameters.ui.h:79 ../gtk/ldap.ui.h:4 msgid "Username:" msgstr "使用者名稱:" -#: ../gtk/setupwizard.c:94 ../gtk/password.ui.h:4 +#: ../gtk/setupwizard.c:98 ../gtk/password.ui.h:4 ../gtk/ldap.ui.h:5 msgid "Password:" msgstr "密碼: " -#: ../gtk/setupwizard.c:114 +#: ../gtk/setupwizard.c:118 msgid "Enter your account informations" msgstr "" -#: ../gtk/setupwizard.c:121 +#: ../gtk/setupwizard.c:125 #, fuzzy msgid "Username*" msgstr "使用者名稱" -#: ../gtk/setupwizard.c:122 +#: ../gtk/setupwizard.c:126 #, fuzzy msgid "Password*" msgstr "密碼" -#: ../gtk/setupwizard.c:125 +#: ../gtk/setupwizard.c:129 msgid "Domain*" msgstr "" -#: ../gtk/setupwizard.c:126 +#: ../gtk/setupwizard.c:130 msgid "Proxy" msgstr "" -#: ../gtk/setupwizard.c:298 +#: ../gtk/setupwizard.c:302 msgid "(*) Required fields" msgstr "" -#: ../gtk/setupwizard.c:299 +#: ../gtk/setupwizard.c:303 #, fuzzy msgid "Username: (*)" msgstr "使用者名稱:" -#: ../gtk/setupwizard.c:301 +#: ../gtk/setupwizard.c:305 #, fuzzy msgid "Password: (*)" msgstr "密碼: " -#: ../gtk/setupwizard.c:303 +#: ../gtk/setupwizard.c:307 msgid "Email: (*)" msgstr "" -#: ../gtk/setupwizard.c:305 +#: ../gtk/setupwizard.c:309 msgid "Confirm your password: (*)" msgstr "" -#: ../gtk/setupwizard.c:369 +#: ../gtk/setupwizard.c:373 msgid "" "Error, account not validated, username already used or server unreachable.\n" "Please go back and try again." msgstr "" -#: ../gtk/setupwizard.c:380 +#: ../gtk/setupwizard.c:384 msgid "Thank you. Your account is now configured and ready for use." msgstr "謝謝您。您的帳號已設定完成並且可以使用。" -#: ../gtk/setupwizard.c:388 +#: ../gtk/setupwizard.c:392 msgid "" "Please validate your account by clicking on the link we just sent you by " "email.\n" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:564 +#: ../gtk/setupwizard.c:572 +#, fuzzy +msgid "SIP account configuration assistant" +msgstr "帳號設定助理" + +#: ../gtk/setupwizard.c:590 msgid "Welcome to the account setup assistant" msgstr "歡迎使用帳號設定助理" -#: ../gtk/setupwizard.c:569 +#: ../gtk/setupwizard.c:595 msgid "Account setup assistant" msgstr "帳號設定助理" -#: ../gtk/setupwizard.c:575 +#: ../gtk/setupwizard.c:601 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "設定 SIP 帳號" -#: ../gtk/setupwizard.c:580 +#: ../gtk/setupwizard.c:606 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:584 +#: ../gtk/setupwizard.c:610 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:593 +#: ../gtk/setupwizard.c:619 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:598 +#: ../gtk/setupwizard.c:624 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:602 +#: ../gtk/setupwizard.c:628 msgid "Terminating" msgstr "" @@ -621,135 +636,150 @@ msgstr "ICE 過濾器" msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:259 ../gtk/incall_view.c:265 +#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:286 +#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#, c-format +msgid "%ix%i" +msgstr "" + +#: ../gtk/incall_view.c:297 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:384 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:476 +#: ../gtk/incall_view.c:487 msgid "Calling..." msgstr "播打..." -#: ../gtk/incall_view.c:479 ../gtk/incall_view.c:689 +#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:490 +#: ../gtk/incall_view.c:501 msgid "Incoming call" msgstr "來電" -#: ../gtk/incall_view.c:527 +#: ../gtk/incall_view.c:538 msgid "good" msgstr "" -#: ../gtk/incall_view.c:529 +#: ../gtk/incall_view.c:540 msgid "average" msgstr "" -#: ../gtk/incall_view.c:531 +#: ../gtk/incall_view.c:542 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:533 +#: ../gtk/incall_view.c:544 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:535 +#: ../gtk/incall_view.c:546 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:536 ../gtk/incall_view.c:552 +#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:651 +#: ../gtk/incall_view.c:662 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:657 +#: ../gtk/incall_view.c:668 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:663 +#: ../gtk/incall_view.c:674 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:663 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:684 +#: ../gtk/incall_view.c:695 msgid "In call" msgstr "通話中" -#: ../gtk/incall_view.c:718 +#: ../gtk/incall_view.c:731 msgid "Paused call" msgstr "暫停通話" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:744 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:748 +#: ../gtk/incall_view.c:762 msgid "Call ended." msgstr "通話結束。" -#: ../gtk/incall_view.c:778 +#: ../gtk/incall_view.c:793 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:781 +#: ../gtk/incall_view.c:796 #, fuzzy msgid "Transfer done." msgstr "轉接" -#: ../gtk/incall_view.c:784 +#: ../gtk/incall_view.c:799 #, fuzzy msgid "Transfer failed." msgstr "轉接" -#: ../gtk/incall_view.c:828 +#: ../gtk/incall_view.c:843 msgid "Resume" msgstr "繼續" -#: ../gtk/incall_view.c:835 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 msgid "Pause" msgstr "暫停" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:900 +#: ../gtk/incall_view.c:915 #, fuzzy msgid "(Paused)" msgstr "暫停" -#: ../gtk/loginframe.c:93 +#: ../gtk/loginframe.c:88 #, c-format msgid "Please enter login information for %s" msgstr "請輸入 %s 的 登入資訊" +#: ../gtk/config-fetching.c:57 +#, c-format +msgid "fetching from %s" +msgstr "" + +#: ../gtk/config-fetching.c:73 +#, c-format +msgid "Downloading of remote configuration from %s failed." +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -796,91 +826,92 @@ msgid "_Options" msgstr "選項(_O)" #: ../gtk/main.ui.h:18 +#, fuzzy +msgid "Set configuration URI" +msgstr "確認" + +#: ../gtk/main.ui.h:19 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:20 msgid "Enable self-view" msgstr "啟用自拍檢視" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:21 msgid "_Help" msgstr "求助(_H)" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:22 msgid "Show debug window" msgstr "顯示除錯視窗" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:23 msgid "_Homepage" msgstr "官方網頁(_H)" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:24 msgid "Check _Updates" msgstr "檢查更新(_U)" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:25 #, fuzzy msgid "Account assistant" msgstr "帳號設定助理" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:26 msgid "SIP address or phone number:" msgstr "SIP 位址或電話號碼:" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:27 msgid "Initiate a new call" msgstr "打出新電話" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:28 msgid "Contacts" msgstr "連絡人" -#: ../gtk/main.ui.h:28 ../gtk/parameters.ui.h:50 -msgid "Add" -msgstr "加入" - -#: ../gtk/main.ui.h:29 ../gtk/parameters.ui.h:51 -msgid "Edit" -msgstr "編輯" - -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:29 msgid "Search" msgstr "搜尋" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:30 msgid "Add contacts from directory" msgstr "從目錄加入連絡人" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:31 msgid "Add contact" msgstr "加入聯絡人" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:32 #, fuzzy msgid "Recent calls" msgstr "通話中" -#: ../gtk/main.ui.h:34 +#: ../gtk/main.ui.h:33 msgid "My current identity:" msgstr "我目前的使用者識別:" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "使用者名稱" -#: ../gtk/main.ui.h:36 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "密碼" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:36 msgid "Internet connection:" msgstr "網路連線:" -#: ../gtk/main.ui.h:38 +#: ../gtk/main.ui.h:37 msgid "Automatically log me in" msgstr "將我自動登入" +#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "使用者ID" + #: ../gtk/main.ui.h:39 msgid "Login information" msgstr "登入資訊" @@ -926,6 +957,7 @@ msgid "An internet video phone using the standard SIP (rfc3261) protocol." msgstr "使用標準 SIP (rfc3261) 通訊協定的網路視訊電話。" #: ../gtk/about.ui.h:5 +#, fuzzy msgid "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -938,6 +970,7 @@ msgid "" "pl: Robert Nasiadek \n" "cs: Petr Pisar \n" "hu: anonymous\n" +"he: Eli Zaretskii \n" msgstr "" "fr: Simon Morlat\n" "en: Simon Morlat and Delphine Perreau\n" @@ -983,10 +1016,6 @@ msgstr "Linphone - 需要驗證" msgid "Please enter the domain password" msgstr "請輸入這個網域的密碼" -#: ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "使用者ID" - #: ../gtk/call_logs.ui.h:1 msgid "Call history" msgstr "通話紀錄" @@ -1024,305 +1053,372 @@ msgid "Looks like sip:" msgstr "看起來像 sip:" #: ../gtk/sip_account.ui.h:7 -msgid "Route (optional):" -msgstr "路由 (選擇性):" - -#: ../gtk/sip_account.ui.h:8 msgid "Registration duration (sec):" msgstr "註冊時間 (秒):" +#: ../gtk/sip_account.ui.h:8 +#, fuzzy +msgid "Contact params (optional):" +msgstr "路由 (選擇性):" + #: ../gtk/sip_account.ui.h:9 +msgid "Route (optional):" +msgstr "路由 (選擇性):" + +#: ../gtk/sip_account.ui.h:10 +#, fuzzy +msgid "Transport" +msgstr "傳輸" + +#: ../gtk/sip_account.ui.h:11 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:12 msgid "Publish presence information" msgstr "發布上線資訊" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:13 msgid "Configure a SIP account" msgstr "設定 SIP 帳號" #: ../gtk/parameters.ui.h:1 +msgid "anonymous" +msgstr "" + +#: ../gtk/parameters.ui.h:2 +msgid "GSSAPI" +msgstr "" + +#: ../gtk/parameters.ui.h:3 +msgid "SASL" +msgstr "" + +#: ../gtk/parameters.ui.h:4 msgid "default soundcard" msgstr "預設的音效卡" -#: ../gtk/parameters.ui.h:2 +#: ../gtk/parameters.ui.h:5 msgid "a sound card" msgstr "音效卡" -#: ../gtk/parameters.ui.h:3 +#: ../gtk/parameters.ui.h:6 msgid "default camera" msgstr "預設的攝影機" -#: ../gtk/parameters.ui.h:4 +#: ../gtk/parameters.ui.h:7 msgid "CIF" msgstr "CIF" -#: ../gtk/parameters.ui.h:5 +#: ../gtk/parameters.ui.h:8 msgid "Audio codecs" msgstr "音訊編碼解碼器" -#: ../gtk/parameters.ui.h:6 +#: ../gtk/parameters.ui.h:9 msgid "Video codecs" msgstr "視訊編碼解碼器" -#: ../gtk/parameters.ui.h:7 ../gtk/keypad.ui.h:5 +#: ../gtk/parameters.ui.h:10 ../gtk/keypad.ui.h:5 msgid "C" msgstr "C" -#: ../gtk/parameters.ui.h:8 +#: ../gtk/parameters.ui.h:11 #, fuzzy msgid "SIP (UDP)" msgstr "SIP (UDP):" -#: ../gtk/parameters.ui.h:9 +#: ../gtk/parameters.ui.h:12 #, fuzzy msgid "SIP (TCP)" msgstr "SIP (TCP):" -#: ../gtk/parameters.ui.h:10 +#: ../gtk/parameters.ui.h:13 #, fuzzy msgid "SIP (TLS)" msgstr "SIP (TCP):" -#: ../gtk/parameters.ui.h:11 +#: ../gtk/parameters.ui.h:14 msgid "Settings" msgstr "設定值" -#: ../gtk/parameters.ui.h:12 +#: ../gtk/parameters.ui.h:15 msgid "Set Maximum Transmission Unit:" msgstr "設定最大傳輸單位:" -#: ../gtk/parameters.ui.h:13 +#: ../gtk/parameters.ui.h:16 msgid "Send DTMFs as SIP info" msgstr "傳送 DTMFs 為 SIP 資訊" -#: ../gtk/parameters.ui.h:14 +#: ../gtk/parameters.ui.h:17 msgid "Use IPv6 instead of IPv4" msgstr "使用 IPv6 代替 IPv4" -#: ../gtk/parameters.ui.h:15 +#: ../gtk/parameters.ui.h:18 msgid "Transport" msgstr "傳輸" -#: ../gtk/parameters.ui.h:16 +#: ../gtk/parameters.ui.h:19 msgid "Media encryption type" msgstr "" -#: ../gtk/parameters.ui.h:17 +#: ../gtk/parameters.ui.h:20 msgid "Video RTP/UDP:" msgstr "視訊 RTP/UDP:" -#: ../gtk/parameters.ui.h:18 +#: ../gtk/parameters.ui.h:21 msgid "Audio RTP/UDP:" msgstr "音效 RTP/UDP:" -#: ../gtk/parameters.ui.h:19 -msgid "DSCP fields" -msgstr "" - -#: ../gtk/parameters.ui.h:20 +#: ../gtk/parameters.ui.h:22 msgid "Fixed" msgstr "" -#: ../gtk/parameters.ui.h:21 -msgid "Tunnel" -msgstr "" - -#: ../gtk/parameters.ui.h:22 +#: ../gtk/parameters.ui.h:23 msgid "Media encryption is mandatory" msgstr "" -#: ../gtk/parameters.ui.h:23 +#: ../gtk/parameters.ui.h:24 +msgid "Tunnel" +msgstr "" + +#: ../gtk/parameters.ui.h:25 +msgid "DSCP fields" +msgstr "" + +#: ../gtk/parameters.ui.h:26 +msgid "SIP/TCP port" +msgstr "" + +#: ../gtk/parameters.ui.h:27 +msgid "SIP/UDP port" +msgstr "" + +#: ../gtk/parameters.ui.h:28 msgid "Network protocol and ports" msgstr "" -#: ../gtk/parameters.ui.h:24 +#: ../gtk/parameters.ui.h:29 msgid "Direct connection to the Internet" msgstr "直接連線到網際網路" -#: ../gtk/parameters.ui.h:25 -msgid "Behind NAT / Firewall (specify gateway IP below)" +#: ../gtk/parameters.ui.h:30 +#, fuzzy +msgid "Behind NAT / Firewall (specify gateway IP )" msgstr "在 NAT / 防火牆之後 (在下面指定閘道器 IP)" -#: ../gtk/parameters.ui.h:26 -msgid "Public IP address:" -msgstr "公共 IP 地址:" - -#: ../gtk/parameters.ui.h:27 +#: ../gtk/parameters.ui.h:31 msgid "Behind NAT / Firewall (use STUN to resolve)" msgstr "在 NAT / 防火牆之後 (使用 STUN 解析)" -#: ../gtk/parameters.ui.h:28 +#: ../gtk/parameters.ui.h:32 #, fuzzy msgid "Behind NAT / Firewall (use ICE)" msgstr "在 NAT / 防火牆之後 (使用 STUN 解析)" -#: ../gtk/parameters.ui.h:29 +#: ../gtk/parameters.ui.h:33 #, fuzzy msgid "Behind NAT / Firewall (use uPnP)" msgstr "在 NAT / 防火牆之後 (使用 STUN 解析)" -#: ../gtk/parameters.ui.h:30 +#: ../gtk/parameters.ui.h:34 +msgid "Public IP address:" +msgstr "公共 IP 地址:" + +#: ../gtk/parameters.ui.h:35 msgid "Stun server:" msgstr "Stun 伺服器:" -#: ../gtk/parameters.ui.h:31 +#: ../gtk/parameters.ui.h:36 msgid "NAT and Firewall" msgstr "NAT 與防火牆" -#: ../gtk/parameters.ui.h:32 +#: ../gtk/parameters.ui.h:37 msgid "Network settings" msgstr "網路設定值" -#: ../gtk/parameters.ui.h:33 +#: ../gtk/parameters.ui.h:38 msgid "Ring sound:" msgstr "鈴聲音效:" -#: ../gtk/parameters.ui.h:34 +#: ../gtk/parameters.ui.h:39 msgid "ALSA special device (optional):" msgstr "ALSA 特殊裝置 (選擇性):" -#: ../gtk/parameters.ui.h:35 +#: ../gtk/parameters.ui.h:40 msgid "Capture device:" msgstr "捕捉裝置:" -#: ../gtk/parameters.ui.h:36 +#: ../gtk/parameters.ui.h:41 msgid "Ring device:" msgstr "響鈴裝置:" -#: ../gtk/parameters.ui.h:37 +#: ../gtk/parameters.ui.h:42 msgid "Playback device:" msgstr "播放裝置" -#: ../gtk/parameters.ui.h:38 +#: ../gtk/parameters.ui.h:43 msgid "Enable echo cancellation" msgstr "啟用回音消除" -#: ../gtk/parameters.ui.h:39 +#: ../gtk/parameters.ui.h:44 msgid "Audio" msgstr "音效" -#: ../gtk/parameters.ui.h:40 +#: ../gtk/parameters.ui.h:45 msgid "Video input device:" msgstr "視訊輸入裝置:" -#: ../gtk/parameters.ui.h:41 +#: ../gtk/parameters.ui.h:46 msgid "Prefered video resolution:" msgstr "偏好的視訊解析度:" -#: ../gtk/parameters.ui.h:42 +#: ../gtk/parameters.ui.h:47 +#, fuzzy +msgid "Video output method:" +msgstr "視訊輸入裝置:" + +#: ../gtk/parameters.ui.h:48 msgid "Video" msgstr "視訊" -#: ../gtk/parameters.ui.h:43 +#: ../gtk/parameters.ui.h:49 msgid "Multimedia settings" msgstr "多媒體設定值" -#: ../gtk/parameters.ui.h:44 +#: ../gtk/parameters.ui.h:50 msgid "This section defines your SIP address when not using a SIP account" msgstr "這一區在不使用 SIP 帳號時定義您的 SIP 位址" -#: ../gtk/parameters.ui.h:45 +#: ../gtk/parameters.ui.h:51 msgid "Your display name (eg: John Doe):" msgstr "您的顯示名稱 (例如: John Doe):" -#: ../gtk/parameters.ui.h:46 +#: ../gtk/parameters.ui.h:52 msgid "Your username:" msgstr "您的使用者名稱:" -#: ../gtk/parameters.ui.h:47 +#: ../gtk/parameters.ui.h:53 msgid "Your resulting SIP address:" msgstr "您組成的 SIP 位址:" -#: ../gtk/parameters.ui.h:48 +#: ../gtk/parameters.ui.h:54 msgid "Default identity" msgstr "預設身分識別" -#: ../gtk/parameters.ui.h:49 +#: ../gtk/parameters.ui.h:55 msgid "Wizard" msgstr "" -#: ../gtk/parameters.ui.h:52 +#: ../gtk/parameters.ui.h:56 +msgid "Add" +msgstr "加入" + +#: ../gtk/parameters.ui.h:57 +msgid "Edit" +msgstr "編輯" + +#: ../gtk/parameters.ui.h:58 msgid "Remove" msgstr "移除" -#: ../gtk/parameters.ui.h:53 +#: ../gtk/parameters.ui.h:59 msgid "Proxy accounts" msgstr "代理伺服器帳號" -#: ../gtk/parameters.ui.h:54 +#: ../gtk/parameters.ui.h:60 msgid "Erase all passwords" msgstr "消除所有的密碼" -#: ../gtk/parameters.ui.h:55 +#: ../gtk/parameters.ui.h:61 msgid "Privacy" msgstr "隱私" -#: ../gtk/parameters.ui.h:56 +#: ../gtk/parameters.ui.h:62 msgid "Manage SIP Accounts" msgstr "管理 SIP 帳號" -#: ../gtk/parameters.ui.h:57 ../gtk/tunnel_config.ui.h:4 +#: ../gtk/parameters.ui.h:63 ../gtk/tunnel_config.ui.h:4 msgid "Enable" msgstr "啟用" -#: ../gtk/parameters.ui.h:58 ../gtk/tunnel_config.ui.h:5 +#: ../gtk/parameters.ui.h:64 ../gtk/tunnel_config.ui.h:5 msgid "Disable" msgstr "停用" -#: ../gtk/parameters.ui.h:59 +#: ../gtk/parameters.ui.h:65 msgid "Codecs" msgstr "編碼解碼器" -#: ../gtk/parameters.ui.h:60 +#: ../gtk/parameters.ui.h:66 msgid "0 stands for \"unlimited\"" msgstr "0 表示「不限制」" -#: ../gtk/parameters.ui.h:61 +#: ../gtk/parameters.ui.h:67 msgid "Upload speed limit in Kbit/sec:" msgstr "上傳速度限制於 Kbit/sec:" -#: ../gtk/parameters.ui.h:62 +#: ../gtk/parameters.ui.h:68 msgid "Download speed limit in Kbit/sec:" msgstr "下載速度限制於 Kbit/sec:" -#: ../gtk/parameters.ui.h:63 +#: ../gtk/parameters.ui.h:69 msgid "Enable adaptive rate control" msgstr "" -#: ../gtk/parameters.ui.h:64 +#: ../gtk/parameters.ui.h:70 msgid "" "Adaptive rate control is a technique to dynamically guess the available " "bandwidth during a call." msgstr "" -#: ../gtk/parameters.ui.h:65 +#: ../gtk/parameters.ui.h:71 msgid "Bandwidth control" msgstr "頻寬控制" -#: ../gtk/parameters.ui.h:66 +#: ../gtk/parameters.ui.h:72 msgid "Codecs" msgstr "編碼解碼器" -#: ../gtk/parameters.ui.h:67 +#: ../gtk/parameters.ui.h:73 msgid "Language" msgstr "語言" -#: ../gtk/parameters.ui.h:68 +#: ../gtk/parameters.ui.h:74 msgid "Show advanced settings" msgstr "顯示進階設定值" -#: ../gtk/parameters.ui.h:69 +#: ../gtk/parameters.ui.h:75 msgid "Level" msgstr "級數" -#: ../gtk/parameters.ui.h:70 +#: ../gtk/parameters.ui.h:76 msgid "User interface" msgstr "使用者介面" -#: ../gtk/parameters.ui.h:71 +#: ../gtk/parameters.ui.h:77 ../gtk/ldap.ui.h:2 +#, fuzzy +msgid "Server address:" +msgstr "SIP 代理位址:" + +#: ../gtk/parameters.ui.h:78 ../gtk/ldap.ui.h:3 +#, fuzzy +msgid "Authentication method:" +msgstr "驗證失敗" + +#: ../gtk/parameters.ui.h:80 +msgid "label" +msgstr "標籤" + +#: ../gtk/parameters.ui.h:81 +#, fuzzy +msgid "LDAP Account setup" +msgstr "代理伺服器帳號" + +#: ../gtk/parameters.ui.h:82 +msgid "LDAP" +msgstr "" + +#: ../gtk/parameters.ui.h:83 msgid "Done" msgstr "完成" @@ -1348,7 +1444,7 @@ msgstr "請稍候" #: ../gtk/dscp_settings.ui.h:1 #, fuzzy -msgid "Dscp settings" +msgid "DSCP settings" msgstr "設定值" #: ../gtk/dscp_settings.ui.h:2 @@ -1404,6 +1500,15 @@ msgid "Round trip time" msgstr "" #: ../gtk/call_statistics.ui.h:9 +msgid "Video resolution received" +msgstr "" + +#: ../gtk/call_statistics.ui.h:10 +#, fuzzy +msgid "Video resolution sent" +msgstr "偏好的視訊解析度:" + +#: ../gtk/call_statistics.ui.h:11 #, fuzzy msgid "Call statistics and information" msgstr "連絡人資訊" @@ -1489,19 +1594,140 @@ msgstr "2" msgid "1" msgstr "1" -#: ../coreapi/linphonecore.c:228 +#: ../gtk/ldap.ui.h:1 +#, fuzzy +msgid "LDAP Settings" +msgstr "設定值" + +#: ../gtk/ldap.ui.h:6 +msgid "Use TLS Connection" +msgstr "" + +#: ../gtk/ldap.ui.h:7 +msgid "Not yet available" +msgstr "" + +#: ../gtk/ldap.ui.h:8 +#, fuzzy +msgid "Connection" +msgstr "編碼解碼器" + +#: ../gtk/ldap.ui.h:9 +msgid "Bind DN" +msgstr "" + +#: ../gtk/ldap.ui.h:10 +msgid "Authname" +msgstr "" + +#: ../gtk/ldap.ui.h:11 +msgid "Realm" +msgstr "" + +#: ../gtk/ldap.ui.h:12 +#, fuzzy +msgid "SASL" +msgstr "音效" + +#: ../gtk/ldap.ui.h:13 +msgid "Base object:" +msgstr "" + +#: ../gtk/ldap.ui.h:15 +#, no-c-format +msgid "Filter (%s for name):" +msgstr "" + +#: ../gtk/ldap.ui.h:16 +msgid "Name Attribute:" +msgstr "" + +#: ../gtk/ldap.ui.h:17 +#, fuzzy +msgid "SIP address attribute:" +msgstr "SIP 位址或電話號碼:" + +#: ../gtk/ldap.ui.h:18 +msgid "Attributes to query:" +msgstr "" + +#: ../gtk/ldap.ui.h:19 +#, fuzzy +msgid "Search" +msgstr "搜尋某人" + +#: ../gtk/ldap.ui.h:20 +msgid "Timeout for search:" +msgstr "" + +#: ../gtk/ldap.ui.h:21 +msgid "Max results:" +msgstr "" + +#: ../gtk/ldap.ui.h:22 +msgid "Follow Aliases" +msgstr "" + +#: ../gtk/ldap.ui.h:23 +#, fuzzy +msgid "Miscellaneous" +msgstr "視訊" + +#: ../gtk/ldap.ui.h:24 +msgid "ANONYMOUS" +msgstr "" + +#: ../gtk/ldap.ui.h:25 +msgid "SIMPLE" +msgstr "" + +#: ../gtk/ldap.ui.h:26 +msgid "DIGEST-MD5" +msgstr "" + +#: ../gtk/ldap.ui.h:27 +msgid "NTLM" +msgstr "" + +#: ../gtk/config-uri.ui.h:1 +msgid "Specifying a remote configuration URI" +msgstr "" + +#: ../gtk/config-uri.ui.h:2 +msgid "" +"This dialog allows to set an http or https address when configuration is to " +"be fetched at startup.\n" +"Please enter or modify the configuration URI below. After clicking OK, " +"Linphone will restart automatically in order to fetch and take into account " +"the new configuration. " +msgstr "" + +#: ../gtk/config-uri.ui.h:4 +msgid "https://" +msgstr "" + +#: ../gtk/provisioning-fetch.ui.h:1 +#, fuzzy +msgid "Configuring..." +msgstr "連線中..." + +#: ../gtk/provisioning-fetch.ui.h:2 +msgid "Please wait while fetching configuration from server..." +msgstr "" + +#: ../coreapi/linphonecore.c:238 msgid "aborted" msgstr "已放棄" -#: ../coreapi/linphonecore.c:231 +#: ../coreapi/linphonecore.c:241 msgid "completed" msgstr "已完成" -#: ../coreapi/linphonecore.c:234 +#: ../coreapi/linphonecore.c:244 msgid "missed" msgstr "未接" -#: ../coreapi/linphonecore.c:239 +#: ../coreapi/linphonecore.c:249 #, c-format msgid "" "%s at %s\n" @@ -1516,101 +1742,77 @@ msgstr "" "狀態:%s\n" "持續時間:%i 分 %i 秒\n" -#: ../coreapi/linphonecore.c:240 +#: ../coreapi/linphonecore.c:250 msgid "Outgoing call" msgstr "去電" -#: ../coreapi/linphonecore.c:1321 +#: ../coreapi/linphonecore.c:1264 msgid "Ready" msgstr "準備就緒" -#: ../coreapi/linphonecore.c:2205 +#: ../coreapi/linphonecore.c:1372 +#, fuzzy +msgid "Configuring" +msgstr "確認" + +#: ../coreapi/linphonecore.c:2331 msgid "Looking for telephone number destination..." msgstr "尋找電話號碼目的端..." -#: ../coreapi/linphonecore.c:2208 +#: ../coreapi/linphonecore.c:2334 msgid "Could not resolve this number." msgstr "無法解析這個號碼。" -#: ../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:2453 +#. must be known at that time +#: ../coreapi/linphonecore.c:2609 msgid "Contacting" msgstr "正在連絡" -#: ../coreapi/linphonecore.c:2460 +#: ../coreapi/linphonecore.c:2616 msgid "Could not call" msgstr "無法通話" -#: ../coreapi/linphonecore.c:2570 +#: ../coreapi/linphonecore.c:2765 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "抱歉,我們已達瀏同步通話的最大數目" -#: ../coreapi/linphonecore.c:2752 +#: ../coreapi/linphonecore.c:2952 msgid "is contacting you" msgstr "正在連絡您" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid " and asked autoanswer." msgstr "並要求自動接聽。" -#: ../coreapi/linphonecore.c:2753 +#: ../coreapi/linphonecore.c:2953 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:2820 +#: ../coreapi/linphonecore.c:3020 msgid "Modifying call parameters..." msgstr "修改通話參數..." -#: ../coreapi/linphonecore.c:3159 +#: ../coreapi/linphonecore.c:3362 msgid "Connected." msgstr "已連線。" -#: ../coreapi/linphonecore.c:3187 +#: ../coreapi/linphonecore.c:3388 msgid "Call aborted" msgstr "通話已放棄" -#: ../coreapi/linphonecore.c:3378 +#: ../coreapi/linphonecore.c:3581 msgid "Could not pause the call" msgstr "無法暫停通話" -#: ../coreapi/linphonecore.c:3383 +#: ../coreapi/linphonecore.c:3586 msgid "Pausing the current call..." msgstr "暫停目前的通話..." -#: ../coreapi/misc.c:148 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the pcm oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -"'modprobe snd-pcm-oss' as root to load it." -msgstr "" -"您的電腦似乎是使用 ALSA 音效驅動程式。\n" -"這是最好的選擇。然而缺少了 pcm oss 模擬模組\n" -"而 linphone 需要它。請以 root 執行\n" -"'modprobe snd-pcm-oss' 載入它。" - -#: ../coreapi/misc.c:151 -msgid "" -"Your computer appears to be using ALSA sound drivers.\n" -"This is the best choice. However the mixer oss emulation module\n" -"is missing and linphone needs it. Please execute\n" -" 'modprobe snd-mixer-oss' as root to load it." -msgstr "" -"您的電腦似乎是使用 ALSA 音效驅動程式。\n" -"這是最好的選擇。然而缺少了 mixer oss 模擬模組\n" -"而 linphone 需要它。請以 root 執行\n" -"'modprobe snd-mixer-oss' 載入它。" - -#: ../coreapi/misc.c:496 +#: ../coreapi/misc.c:394 msgid "Stun lookup in progress..." msgstr "正在進行 Stun 搜尋..." -#: ../coreapi/misc.c:630 +#: ../coreapi/misc.c:576 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1659,17 +1861,22 @@ msgid "Pending" msgstr "等待中" #: ../coreapi/friend.c:66 +#, fuzzy +msgid "Vacation" +msgstr "時間長度" + +#: ../coreapi/friend.c:68 msgid "Unknown-bug" msgstr "不明錯誤" -#: ../coreapi/proxy.c:204 +#: ../coreapi/proxy.c:209 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" "您輸入的 sip 代理位址是無效的,它必須要以「sip:」開頭,後面接主機名稱。" -#: ../coreapi/proxy.c:210 +#: ../coreapi/proxy.c:215 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1677,132 +1884,160 @@ msgstr "" "您輸入的 sip 身分是無效的。\n" "它應該看起來像 sip:使用者名稱@代理網域,像是 sip:alice@example.net" -#: ../coreapi/proxy.c:1069 +#: ../coreapi/proxy.c:1125 #, c-format msgid "Could not login as %s" msgstr "無法以 %s 登入" -#: ../coreapi/callbacks.c:286 +#: ../coreapi/callbacks.c:289 msgid "Remote ringing." msgstr "遠端響鈴。" -#: ../coreapi/callbacks.c:306 +#: ../coreapi/callbacks.c:305 msgid "Remote ringing..." msgstr "遠端響鈴..." -#: ../coreapi/callbacks.c:317 +#: ../coreapi/callbacks.c:316 msgid "Early media." msgstr "早期媒體。" -#: ../coreapi/callbacks.c:368 +#: ../coreapi/callbacks.c:367 #, c-format msgid "Call with %s is paused." msgstr "和 %s 的通話已暫停。" -#: ../coreapi/callbacks.c:381 +#: ../coreapi/callbacks.c:380 #, c-format msgid "Call answered by %s - on hold." msgstr "通話由 %s 接聽 - 保留中。" -#: ../coreapi/callbacks.c:392 +#: ../coreapi/callbacks.c:391 msgid "Call resumed." msgstr "通話已繼續。" -#: ../coreapi/callbacks.c:397 +#: ../coreapi/callbacks.c:396 #, c-format msgid "Call answered by %s." msgstr "通話由 %s 接聽。" -#: ../coreapi/callbacks.c:412 +#: ../coreapi/callbacks.c:414 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:460 +#: ../coreapi/callbacks.c:463 #, fuzzy msgid "We have been resumed." msgstr "我們要繼續了..." -#: ../coreapi/callbacks.c:469 +#: ../coreapi/callbacks.c:471 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:475 +#: ../coreapi/callbacks.c:487 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:544 +#: ../coreapi/callbacks.c:558 msgid "Call terminated." msgstr "通話已終止。" -#: ../coreapi/callbacks.c:555 +#: ../coreapi/callbacks.c:586 msgid "User is busy." msgstr "使用者現正忙碌。" -#: ../coreapi/callbacks.c:556 +#: ../coreapi/callbacks.c:587 msgid "User is temporarily unavailable." msgstr "使用者暫時無法聯繫。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:589 msgid "User does not want to be disturbed." msgstr "使用者不想要被打擾。" -#: ../coreapi/callbacks.c:559 +#: ../coreapi/callbacks.c:590 msgid "Call declined." msgstr "通話被拒接。" -#: ../coreapi/callbacks.c:571 +#: ../coreapi/callbacks.c:603 msgid "No response." msgstr "沒有回應。" -#: ../coreapi/callbacks.c:575 +#: ../coreapi/callbacks.c:607 msgid "Protocol error." msgstr "通訊協定錯誤。" -#: ../coreapi/callbacks.c:591 +#: ../coreapi/callbacks.c:623 msgid "Redirected" msgstr "已重新導向" -#: ../coreapi/callbacks.c:627 +#: ../coreapi/callbacks.c:665 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:633 +#: ../coreapi/callbacks.c:677 msgid "Call failed." msgstr "通話失敗。" -#: ../coreapi/callbacks.c:737 +#: ../coreapi/callbacks.c:751 #, c-format msgid "Registration on %s successful." msgstr "在 %s 註冊成功。" -#: ../coreapi/callbacks.c:738 +#: ../coreapi/callbacks.c:752 #, c-format msgid "Unregistration on %s done." msgstr "在 %s 取消註冊完成。" -#: ../coreapi/callbacks.c:758 +#: ../coreapi/callbacks.c:772 msgid "no response timeout" msgstr "沒有回應逾時" -#: ../coreapi/callbacks.c:761 +#: ../coreapi/callbacks.c:775 #, c-format msgid "Registration on %s failed: %s" msgstr "在 %s 註冊失敗:%s" -#: ../coreapi/linphonecall.c:129 +#: ../coreapi/callbacks.c:785 +msgid "Service unavailable, retrying" +msgstr "" + +#: ../coreapi/linphonecall.c:142 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "驗證失敗" -#: ../coreapi/linphonecall.c:2355 +#: ../coreapi/linphonecall.c:2678 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您有 %i 通未接來電。" -#~ msgid "label" -#~ msgstr "標籤" +#~ msgid "" +#~ "Could not parse given sip address. A sip url usually looks like sip:" +#~ "user@domain" +#~ msgstr "無法解析指定的 sip 位址。sip 網址通常看起來像 sip:user@domain" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the pcm oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ "'modprobe snd-pcm-oss' as root to load it." +#~ msgstr "" +#~ "您的電腦似乎是使用 ALSA 音效驅動程式。\n" +#~ "這是最好的選擇。然而缺少了 pcm oss 模擬模組\n" +#~ "而 linphone 需要它。請以 root 執行\n" +#~ "'modprobe snd-pcm-oss' 載入它。" + +#~ msgid "" +#~ "Your computer appears to be using ALSA sound drivers.\n" +#~ "This is the best choice. However the mixer oss emulation module\n" +#~ "is missing and linphone needs it. Please execute\n" +#~ " 'modprobe snd-mixer-oss' as root to load it." +#~ msgstr "" +#~ "您的電腦似乎是使用 ALSA 音效驅動程式。\n" +#~ "這是最好的選擇。然而缺少了 mixer oss 模擬模組\n" +#~ "而 linphone 需要它。請以 root 執行\n" +#~ "'modprobe snd-mixer-oss' 載入它。" #~ msgid "Keypad" #~ msgstr "撥號盤" @@ -1834,9 +2069,6 @@ msgstr[0] "您有 %i 通未接來電。" #~ msgid "Verifying" #~ msgstr "檢驗中" -#~ msgid "Confirmation" -#~ msgstr "確認" - #~ msgid "Creating your account" #~ msgstr "正在建立您的帳號" @@ -1869,9 +2101,6 @@ msgstr[0] "您有 %i 通未接來電。" #~ msgid "No common codecs" #~ msgstr "沒有通用的編碼解碼器" -#~ msgid "Authentication failure" -#~ msgstr "驗證失敗" - #~ msgid "Windows" #~ msgstr "視窗" diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 1ba25506d..eb5dfe211 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -462,6 +462,44 @@ static void call_forking_with_push_notification_multiple(void){ linphone_core_manager_destroy(marie2); } +void call_forking_not_responded(void){ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); + MSList* lcs=ms_list_append(NULL,pauline->lc); + + lcs=ms_list_append(lcs,marie->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,marie3->lc); + + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_invite_address(pauline->lc,marie->identity); + /*pauline should hear ringback*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + /*all devices from Marie should be ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + /*nobody answers, flexisip should close the call after XX seconds*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,22000)); + /*all devices should stop ringing*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(marie3); + ms_list_free(lcs); +} + static void early_media_call_forking(void) { LinphoneCoreManager* marie1 = linphone_core_manager_new("marie_early_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new("marie_early_rc"); @@ -559,6 +597,7 @@ test_t flexisip_tests[] = { { "Call forking with urgent reply", call_forking_with_urgent_reply }, { "Call forking with push notification (single)", call_forking_with_push_notification_single }, { "Call forking with push notification (multiple)", call_forking_with_push_notification_multiple }, + { "Call forking not responded", call_forking_not_responded }, { "Early-media call forking", early_media_call_forking }, }; From aad714dbf7f086b0e7780da479fc9ca5950bdea3 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 25 Dec 2013 11:47:20 +0100 Subject: [PATCH 240/439] Add .ui missing file --- gtk/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 1d1be276f..c612ff07d 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -13,7 +13,8 @@ UI_FILES= about.ui \ dscp_settings.ui \ call_statistics.ui \ ldap.ui \ - config-uri.ui + config-uri.ui \ + provisioning-fetch.ui PIXMAPS= \ stock_people.png From 5214931034de70fbf0234711ee4122c15b3cbfae Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 14 Feb 2014 18:03:38 +0100 Subject: [PATCH 241/439] add new log to track auth info added interactively. --- coreapi/authentication.c | 27 +++++++++++++++++++++------ coreapi/callbacks.c | 2 -- coreapi/linphonecore.c | 5 ++++- coreapi/private.h | 5 +---- coreapi/remote_provisioning.c | 16 +++++++++------- gtk/config-fetching.c | 10 +++++----- 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 3b7db3122..4e32d5be3 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -53,7 +53,6 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1); if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm); if (domain!=NULL && (strlen(domain)>0)) obj->domain=ms_strdup(domain); - obj->works=FALSE; return obj; } @@ -65,8 +64,6 @@ LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ if (ai->ha1) obj->ha1=ms_strdup(ai->ha1); if (ai->realm) obj->realm=ms_strdup(ai->realm); if (ai->domain) obj->domain=ms_strdup(ai->domain); - obj->works=FALSE; - obj->usecount=0; return obj; } @@ -337,19 +334,26 @@ LinphoneAuthInfo * linphone_core_create_auth_info(LinphoneCore *lc, const char * * * This information will be used during all SIP transacations that require authentication. **/ -void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) -{ +void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info){ LinphoneAuthInfo *ai; MSList *elem; MSList *l; + int restarted_op_count=0; + bool_t updating=FALSE; + if (info->ha1==NULL && info->passwd==NULL){ + ms_error("linphone_core_add_auth_info(): info supplied with empty password or ha1."); + return; + } /* find if we are attempting to modify an existing auth info */ ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); if (ai!=NULL && ai->domain && info->domain && strcmp(ai->domain, info->domain)==0){ lc->auth_info=ms_list_remove(lc->auth_info,ai); linphone_auth_info_destroy(ai); + updating=TRUE; } lc->auth_info=ms_list_append(lc->auth_info,linphone_auth_info_clone(info)); + /* retry pending authentication operations */ for(l=elem=sal_get_pending_auths(lc->sal);elem!=NULL;elem=elem->next){ SalOp *op=(SalOp*)elem->data; @@ -372,9 +376,20 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) } } sal_op_authenticate(op,&sai); - ai->usecount++; + restarted_op_count++; } } + if (l){ + ms_message("linphone_core_add_auth_info(): restarted [%i] operation(s) after %s auth info for\n" + "\tusername: [%s]\n" + "\trealm [%s]\n" + "\tdomain [%s]\n", + restarted_op_count, + updating ? "updating" : "adding", + info->username ? info->username : "", + info->realm ? info->realm : "", + info->domain ? info->domain : ""); + } ms_list_free(l); write_auth_infos(lc); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 13ac204f7..2a98769e7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -952,8 +952,6 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { sai->userid=ms_strdup(ai->userid?ai->userid:ai->username); sai->password=ai->passwd?ms_strdup(ai->passwd):NULL; sai->ha1=ai->ha1?ms_strdup(ai->ha1):NULL; - ai->usecount++; - ai->last_use_time=ms_time(NULL); return TRUE; } else { return FALSE; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index be3107b01..91f82e770 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1374,7 +1374,10 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); if (remote_provisioning_uri) { - linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri); + int err=linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri); + if (err==-1){ + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI"); + } } else { linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); } diff --git a/coreapi/private.h b/coreapi/private.h index 89d4ae7b1..1c9c8e5a1 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -427,9 +427,6 @@ struct _LinphoneAuthInfo char *passwd; char *ha1; char *domain; - int usecount; - time_t last_use_time; - bool_t works; }; typedef enum _LinphoneIsComposingState { @@ -811,7 +808,7 @@ void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); ****************************************************************************/ void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message); -void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri); +int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri); /***************************************************************************** diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c index 99b4c1292..1749fa317 100644 --- a/coreapi/remote_provisioning.c +++ b/coreapi/remote_provisioning.c @@ -79,22 +79,24 @@ static void belle_request_process_auth_requested(void *ctx, belle_sip_auth_event linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http auth requested"); } -void linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri) { +int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri) { + belle_generic_uri_t *uri=belle_generic_uri_parse(remote_provisioning_uri); belle_http_request_listener_callbacks_t belle_request_listener = { belle_request_process_response_event, belle_request_process_io_error, belle_request_process_timeout, belle_request_process_auth_requested }; - belle_http_request_listener_t *listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc); - belle_http_request_t *request = belle_http_request_create( - "GET", - belle_generic_uri_parse(remote_provisioning_uri), - NULL - ); + belle_http_request_t *request; + if (uri==NULL) { + belle_sip_error("Invalid provisioning URI [%s]",remote_provisioning_uri); + return -1; + } + request=belle_http_request_create("GET",uri, NULL); belle_http_provider_send_request(lc->http_provider, request, listener); + return 0; } void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char*uri){ diff --git a/gtk/config-fetching.c b/gtk/config-fetching.c index bc7a44336..e275662e1 100644 --- a/gtk/config-fetching.c +++ b/gtk/config-fetching.c @@ -33,11 +33,11 @@ void linphone_gtk_config_uri_changed(GtkWidget *button){ GtkWidget *w=gtk_widget_get_toplevel(button); GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry"); const char *uri=gtk_entry_get_text(GTK_ENTRY(entry)); - if (uri && strcmp(uri,"https://")!=0){/*not just the hint text*/ - /*set provisionning uri to the core*/ - linphone_core_set_provisioning_uri(linphone_gtk_get_core(),uri); - gtk_widget_destroy(w); - } + + if (uri && (strlen(uri)==0 || strcmp(uri,"https://")==0)) uri=NULL; + + linphone_core_set_provisioning_uri(linphone_gtk_get_core(),uri); + gtk_widget_destroy(w); if (uri){ linphone_gtk_schedule_restart(); From c74da6e6d00b2547e2dc0b915c372493751e6ec5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 17 Feb 2014 11:44:36 +0100 Subject: [PATCH 242/439] Fix some tests for Android --- tester/Makefile.am | 2 +- tester/flexisip_tester.c | 26 +++++++++++------------ tester/{pauline_rc_tcp => pauline_tcp_rc} | 0 tester/remote_provisioning_tester.c | 11 ++++++---- tester/setup_tester.c | 7 +++--- 5 files changed, 24 insertions(+), 22 deletions(-) rename tester/{pauline_rc_tcp => pauline_tcp_rc} (100%) diff --git a/tester/Makefile.am b/tester/Makefile.am index 22949b61f..dde662c18 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -1,6 +1,6 @@ EXTRA_DIST= empty_rc laure_rc marie_early_rc marie_no_sdp_rc marie_rc multi_account_lrc pauline_alt_rc \ marie_remote_rc pauline_remote_rc marie_remote_404_rc marie_remote_invalid_rc \ - pauline_rc pauline_wild_rc pauline_rc_tcp tester_hosts sounds images certificates + pauline_rc pauline_wild_rc pauline_tcp_rc tester_hosts sounds images certificates if BUILD_CUNIT_TESTS diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index eb5dfe211..40cab9b95 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -25,8 +25,8 @@ static void subscribe_forking(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); - LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCoreManager* pauline2 = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneContent content={0}; LinphoneEvent *lev; int expires= 600; @@ -59,7 +59,7 @@ static void subscribe_forking(void) { } static void message_forking(void) { - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); MSList* lcs=ms_list_append(NULL,marie->lc); @@ -83,7 +83,7 @@ static void message_forking(void) { } static void message_forking_with_unreachable_recipients(void) { - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); @@ -125,7 +125,7 @@ static void message_forking_with_unreachable_recipients(void) { } static void message_forking_with_all_recipients_unreachable(void) { - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); @@ -175,7 +175,7 @@ static void message_forking_with_all_recipients_unreachable(void) { } static void call_forking(void){ - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); @@ -221,7 +221,7 @@ static void call_forking(void){ } static void call_forking_with_urgent_reply(void){ - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); @@ -266,7 +266,7 @@ static void call_forking_with_urgent_reply(void){ } static void call_forking_cancelled(void){ - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); @@ -306,7 +306,7 @@ static void call_forking_cancelled(void){ } static void call_forking_declined(bool_t declined_globaly){ - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); @@ -369,7 +369,7 @@ static void call_forking_declined_localy(void){ } static void call_forking_with_push_notification_single(void){ - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); @@ -411,7 +411,7 @@ static void call_forking_with_push_notification_single(void){ } static void call_forking_with_push_notification_multiple(void){ - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); @@ -463,7 +463,7 @@ static void call_forking_with_push_notification_multiple(void){ } void call_forking_not_responded(void){ - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie3 = linphone_core_manager_new( "marie_rc"); @@ -503,7 +503,7 @@ void call_forking_not_responded(void){ 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_tcp"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); MSList *lcs=NULL; LinphoneCallParams *params=linphone_core_create_default_call_parameters(pauline->lc); LinphoneVideoPolicy pol; diff --git a/tester/pauline_rc_tcp b/tester/pauline_tcp_rc similarity index 100% rename from tester/pauline_rc_tcp rename to tester/pauline_tcp_rc diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 27cd34d89..95362b5a9 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -42,26 +42,29 @@ static void remote_provisioning_skipped(void) { } static void remote_provisioning_http(void) { - LinphoneCoreManager* marie = linphone_core_manager_new("marie_remote_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_rc", FALSE); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneRegistrationOk,1)); linphone_core_manager_destroy(marie); } static void remote_provisioning_https(void) { - LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_remote_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new2("pauline_remote_rc", FALSE); + char rootcapath[256] = {0}; + snprintf(rootcapath, sizeof(rootcapath), "%s/rootca.pem", liblinphone_tester_file_prefix); + linphone_core_set_root_ca(pauline->lc, rootcapath); CU_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneConfiguringSuccessful,1)); linphone_core_manager_destroy(pauline); } static void remote_provisioning_not_found(void) { - LinphoneCoreManager* marie = linphone_core_manager_new("marie_remote_404_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_404_rc", FALSE); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringFailed,1)); linphone_core_manager_destroy(marie); } static void remote_provisioning_invalid(void) { - LinphoneCoreManager* marie = linphone_core_manager_new("marie_remote_invalid_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_invalid_rc", FALSE); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringFailed,1)); linphone_core_manager_destroy(marie); } diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 1b854baba..31e12a733 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -47,8 +47,8 @@ static void core_sip_transport_test(void) { 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*/ + CU_ASSERT_EQUAL(tr.tcp_port,5060); /*default config*/ + CU_ASSERT_EQUAL(tr.tls_port,LC_SIP_TRANSPORT_RANDOM); /*default config*/ tr.udp_port=LC_SIP_TRANSPORT_RANDOM; tr.tcp_port=LC_SIP_TRANSPORT_RANDOM; @@ -58,8 +58,7 @@ static void core_sip_transport_test(void) { 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_NOT_EQUAL(tr.tcp_port,5060); /*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); From ac5401475166eacf71e9cc947898a0c2cc392ad5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 17 Feb 2014 13:02:55 +0100 Subject: [PATCH 243/439] Few more fixes for the tester --- tester/Makefile.am | 2 +- tester/marie_remote_https_rc | 2 ++ tester/pauline_remote_rc | 2 -- tester/pauline_xml | 45 ----------------------------- tester/remote_provisioning_tester.c | 9 +++--- tester/setup_tester.c | 1 - 6 files changed, 8 insertions(+), 53 deletions(-) create mode 100644 tester/marie_remote_https_rc delete mode 100644 tester/pauline_remote_rc delete mode 100644 tester/pauline_xml diff --git a/tester/Makefile.am b/tester/Makefile.am index dde662c18..f5344b13f 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -1,5 +1,5 @@ EXTRA_DIST= empty_rc laure_rc marie_early_rc marie_no_sdp_rc marie_rc multi_account_lrc pauline_alt_rc \ - marie_remote_rc pauline_remote_rc marie_remote_404_rc marie_remote_invalid_rc \ + marie_remote_rc marie_remote_https_rc marie_remote_404_rc marie_remote_invalid_rc \ pauline_rc pauline_wild_rc pauline_tcp_rc tester_hosts sounds images certificates diff --git a/tester/marie_remote_https_rc b/tester/marie_remote_https_rc new file mode 100644 index 000000000..cc5343c30 --- /dev/null +++ b/tester/marie_remote_https_rc @@ -0,0 +1,2 @@ +[misc] +config-uri=https://smtp.linphone.org/marie_xml diff --git a/tester/pauline_remote_rc b/tester/pauline_remote_rc deleted file mode 100644 index 3594a2f94..000000000 --- a/tester/pauline_remote_rc +++ /dev/null @@ -1,2 +0,0 @@ -[misc] -config-uri=https://smtp.linphone.org/pauline_xml diff --git a/tester/pauline_xml b/tester/pauline_xml deleted file mode 100644 index cc952af82..000000000 --- a/tester/pauline_xml +++ /dev/null @@ -1,45 +0,0 @@ - - -
- -1 - -1 - -1 - 0 - 0 - 0 - 1 -
-
- pauline - pauline - secret - sip.example.org -
-
- sip2.linphone.org;transport=tls - sip2.linphone.org;transport=tls - sip:pauline@sip.example.org - 3600 - 1 - 0 - 0 -
-
- 8090 - 9092 -
-
- 0 - 0 - 0 - vga - 0 - 0 - 0 - 0 - StaticImage: Static picture -
-
- 0 #to not overload cpu in case of VG -
-
diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 95362b5a9..04ced1444 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -49,12 +49,13 @@ static void remote_provisioning_http(void) { } static void remote_provisioning_https(void) { - LinphoneCoreManager* pauline = linphone_core_manager_new2("pauline_remote_rc", FALSE); + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_https_rc", FALSE); char rootcapath[256] = {0}; snprintf(rootcapath, sizeof(rootcapath), "%s/rootca.pem", liblinphone_tester_file_prefix); - linphone_core_set_root_ca(pauline->lc, rootcapath); - CU_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneConfiguringSuccessful,1)); - linphone_core_manager_destroy(pauline); + linphone_core_set_root_ca(marie->lc, rootcapath); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneRegistrationOk,1)); + linphone_core_manager_destroy(marie); } static void remote_provisioning_not_found(void) { diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 31e12a733..0e4299dbc 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -48,7 +48,6 @@ static void core_sip_transport_test(void) { linphone_core_get_sip_transports(lc,&tr); CU_ASSERT_EQUAL(tr.udp_port,5060); /*default config*/ CU_ASSERT_EQUAL(tr.tcp_port,5060); /*default config*/ - CU_ASSERT_EQUAL(tr.tls_port,LC_SIP_TRANSPORT_RANDOM); /*default config*/ tr.udp_port=LC_SIP_TRANSPORT_RANDOM; tr.tcp_port=LC_SIP_TRANSPORT_RANDOM; From 5a41a8525c19d6ba7a396f3e5df446585ea8b91b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 17 Feb 2014 15:51:17 +0100 Subject: [PATCH 244/439] Fix STUN tester when video is not available. --- tester/stun_tester.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tester/stun_tester.c b/tester/stun_tester.c index 0fa91dac5..e416fa02c 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -88,15 +88,19 @@ static void linphone_stun_test_grab_ip() CU_ASSERT( dummy_call.ac.addr[0] != '\0'); CU_ASSERT( dummy_call.ac.port != 0); +#ifdef VIDEO_ENABLED CU_ASSERT( dummy_call.vc.addr[0] != '\0'); CU_ASSERT( dummy_call.vc.port != 0); +#endif ms_message("STUN test result: local audio port maps to %s:%i", dummy_call.ac.addr, dummy_call.ac.port); +#ifdef VIDEO_ENABLED ms_message("STUN test result: local video port maps to %s:%i", dummy_call.vc.addr, dummy_call.vc.port); +#endif linphone_core_manager_destroy(lc_stun); } From 076d87e2af8016ae8d21de142017121b03a6b489 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 17 Feb 2014 16:07:00 +0100 Subject: [PATCH 245/439] Delay remote provisioning until the first linphone_core_iterate --- coreapi/linphonecore.c | 37 ++++++++++++++++++----------- tester/remote_provisioning_tester.c | 3 --- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 91f82e770..b20ea9c8f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1364,23 +1364,11 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab lc->http_provider = belle_sip_stack_create_http_provider(sal_get_belle_sip_stack(lc->sal), "0.0.0.0"); certificates_config_read(lc); - belle_tls_verify_policy_t *tls_policy = belle_tls_verify_policy_new(); - belle_tls_verify_policy_set_root_ca(tls_policy, sal_get_root_ca(lc->sal)); - belle_http_provider_set_tls_verify_policy(lc->http_provider, tls_policy); - - if (lc->vtable.display_status) - lc->vtable.display_status(lc, _("Configuring")); - linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); - if (remote_provisioning_uri) { - int err=linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri); - if (err==-1){ - linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI"); - } - } else { + if (remote_provisioning_uri == NULL) { linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); - } + } // else linphone_core_start will be called after the remote provisioining (see linphone_core_iterate) } /** @@ -2188,6 +2176,27 @@ void linphone_core_iterate(LinphoneCore *lc){ time_t curtime=time(NULL); int elapsed; bool_t one_second_elapsed=FALSE; + const char *remote_provisioning_uri = NULL; + + if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) { + if (sal_get_root_ca(lc->sal)) { + belle_tls_verify_policy_t *tls_policy = belle_tls_verify_policy_new(); + belle_tls_verify_policy_set_root_ca(tls_policy, sal_get_root_ca(lc->sal)); + belle_http_provider_set_tls_verify_policy(lc->http_provider, tls_policy); + } + + if (lc->vtable.display_status) + lc->vtable.display_status(lc, _("Configuring")); + linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); + + remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); + if (remote_provisioning_uri) { + int err = linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri); + if (err == -1) { + linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI"); + } + } // else linphone_configuring_terminated has already been called in linphone_core_init + } if (curtime-lc->prevtime>=1){ lc->prevtime=curtime; diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 04ced1444..1430c31b3 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -50,9 +50,6 @@ static void remote_provisioning_http(void) { static void remote_provisioning_https(void) { LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_https_rc", FALSE); - char rootcapath[256] = {0}; - snprintf(rootcapath, sizeof(rootcapath), "%s/rootca.pem", liblinphone_tester_file_prefix); - linphone_core_set_root_ca(marie->lc, rootcapath); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneRegistrationOk,1)); linphone_core_manager_destroy(marie); From 3a8d2ee20d219432b40cc583dd0d0a3e28e4e7f7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 17 Feb 2014 16:09:18 +0100 Subject: [PATCH 246/439] Added *.linphone.org rootca to pem file used by tester --- tester/certificates/cn/cafile.pem | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tester/certificates/cn/cafile.pem b/tester/certificates/cn/cafile.pem index 2fd957d39..43437333b 100644 --- a/tester/certificates/cn/cafile.pem +++ b/tester/certificates/cn/cafile.pem @@ -18,3 +18,29 @@ axGKc0DjiJPypU/NsAf4Yu0nOnY8pHqJJCB0AWVoAPM7vGYPWpeH7LSdGZLuT9eK FUWGJhPnkrnklmBdVB0l7qXYjR5uf766HDkoDxuLhNifow3IYvsS+L2Y6puRQb9w HLMDE29mBDl0WyoX3h0yR0EiAO15V9A7I10= -----END CERTIFICATE----- + +UTN USERFirst Hardware Root CA, used for *.linphone.org +============================== +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd +BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx +OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 +eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz +ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI +wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd +tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 +i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf +Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw +gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF +lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF +UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW +XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 +lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn +iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 +nfhmqA== +-----END CERTIFICATE----- From 6c8e00e7c148972b8608a1b3718d13882892eb99 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 17 Feb 2014 15:09:02 +0100 Subject: [PATCH 247/439] Fix wizard --- gtk/setupwizard.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c index 7ea6c3295..b418b7104 100644 --- a/gtk/setupwizard.c +++ b/gtk/setupwizard.c @@ -424,20 +424,11 @@ static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page linphone_proxy_config_enable_publish(cfg, FALSE); linphone_proxy_config_enable_register(cfg, TRUE); - gchar *username = creator->username + 4; - const gchar *needle = "@"; - const gchar *needle_ptr = g_strrstr(username, needle); - if (needle_ptr != NULL) { - username = g_strndup(username, needle_ptr - username); - } else { - username = g_strdup(username); - } - gchar domain[128]; - g_snprintf(domain, sizeof(domain), "\"%s\"", creator->domain + 4); - LinphoneAuthInfo *info=linphone_auth_info_new(username, username, creator->password, NULL, NULL, domain); + LinphoneAddress *identity = linphone_address_new(creator->username); + LinphoneAuthInfo *info=linphone_auth_info_new(linphone_address_get_username(identity), NULL, creator->password, NULL, NULL, linphone_address_get_domain(identity)); linphone_core_add_auth_info(linphone_gtk_get_core(),info); - g_free(username); - + linphone_address_destroy(identity); + // If account created on sip.linphone.org, we configure linphone to use TLS by default if (strcmp(creator->domain, "sip:sip.linphone.org") == 0 && linphone_core_sip_transport_supported(linphone_gtk_get_core(),LinphoneTransportTls)) { LinphoneAddress *addr=linphone_address_new(creator->domain); From 4e15c49452d02ca37adefba4235648542e1a53e0 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 17 Feb 2014 17:26:08 +0100 Subject: [PATCH 248/439] Fix friendlist contact name --- gtk/friendlist.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 0316dd699..f86f8b4c6 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -910,7 +910,11 @@ void linphone_gtk_contact_ok(GtkWidget *button){ linphone_friend_set_inc_subscribe_policy(lf,allow_presence ? LinphoneSPAccept : LinphoneSPDeny); linphone_friend_send_subscribe(lf,show_presence); } - name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))); + + name = NULL; + if(gtk_entry_get_text_length(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))) != 0){ + name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))); + } uri=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address"))); show_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence"))); allow_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence"))); @@ -919,9 +923,10 @@ void linphone_gtk_contact_ok(GtkWidget *button){ linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); return ; } - linphone_address_set_display_name(friend_address,name); - linphone_friend_set_address(lf,friend_address); + linphone_address_set_display_name(friend_address,name); + linphone_friend_set_name(lf,name); + linphone_friend_set_address(lf,friend_address); linphone_friend_send_subscribe(lf,show_presence); linphone_friend_set_inc_subscribe_policy(lf,allow_presence==TRUE ? LinphoneSPAccept : LinphoneSPDeny); if (linphone_friend_in_list(lf)) { @@ -931,7 +936,6 @@ void linphone_gtk_contact_ok(GtkWidget *button){ lf2=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri); ms_free(uri); if(lf2==NULL){ - linphone_friend_set_name(lf,name); linphone_core_add_friend(linphone_gtk_get_core(),lf); } } @@ -1112,4 +1116,4 @@ gboolean linphone_gtk_contact_list_button_pressed(GtkWidget *widget, GdkEventBut void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf){ /*refresh the entire list*/ linphone_gtk_show_friends(); -} \ No newline at end of file +} From ec6ce6d79636c83515bed2d2cc98f8a7136eb197 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Feb 2014 10:31:00 +0100 Subject: [PATCH 249/439] fix double initialization of UI at startup --- gtk/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index 01fae0025..307dc7f51 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -2289,8 +2289,6 @@ core_start: gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core()); gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core()); - if (linphone_core_get_global_state(the_core)==LinphoneGlobalOn) linphone_gtk_init_ui(); - gtk_main(); linphone_gtk_quit(); From 3e876562027c51f61e3fe32f37bc66075e0b7854 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 18 Feb 2014 10:50:13 +0100 Subject: [PATCH 250/439] Fix flexisip tester for Android --- tester/flexisip_tester.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 40cab9b95..b2bae56df 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -306,6 +306,7 @@ static void call_forking_cancelled(void){ } static void call_forking_declined(bool_t declined_globaly){ + char hellopath[256]; LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); @@ -321,6 +322,11 @@ static void call_forking_declined(bool_t declined_globaly){ linphone_core_set_user_agent(marie3->lc,"Natted Linphone",NULL); linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + /*use playfile for callee to avoid locking on capture card*/ + linphone_core_use_files (pauline->lc,TRUE); + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + linphone_core_set_play_file(pauline->lc,hellopath); + linphone_core_invite_address(pauline->lc,marie->identity); /*pauline should hear ringback*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); @@ -369,6 +375,7 @@ static void call_forking_declined_localy(void){ } static void call_forking_with_push_notification_single(void){ + char hellopath[256]; LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -382,6 +389,11 @@ static void call_forking_with_push_notification_single(void){ /*unfortunately marie gets unreachable due to crappy 3G operator or iOS bug...*/ linphone_core_set_network_reachable(marie->lc,FALSE); + /*use playfile for callee to avoid locking on capture card*/ + linphone_core_use_files (pauline->lc,TRUE); + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + linphone_core_set_play_file(pauline->lc,hellopath); + linphone_core_invite_address(pauline->lc,marie->identity); /*the server is expected to send a push notification to marie, this will wake up linphone, that will reconnect:*/ @@ -411,6 +423,7 @@ static void call_forking_with_push_notification_single(void){ } static void call_forking_with_push_notification_multiple(void){ + char hellopath[256]; LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc"); @@ -427,6 +440,13 @@ static void call_forking_with_push_notification_multiple(void){ /*unfortunately marie gets unreachable due to crappy 3G operator or iOS bug...*/ linphone_core_set_network_reachable(marie2->lc,FALSE); + /*use playfile for callee to avoid locking on capture card*/ + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + linphone_core_use_files (marie->lc,TRUE); + linphone_core_set_play_file(marie->lc,hellopath); + linphone_core_use_files (marie2->lc,TRUE); + linphone_core_set_play_file(marie2->lc,hellopath); + linphone_core_invite_address(pauline->lc,marie->identity); /*marie1 will ring*/ From 7bfd12788a1753f17a2a054152addfc8d465ebc9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 18 Feb 2014 15:15:55 +0100 Subject: [PATCH 251/439] Added JNI wrapper for LinphoneAddress set/get transport methods --- coreapi/linphonecore_jni.cc | 13 ++++- .../org/linphone/core/LinphoneAddress.java | 47 +++++++++++++++++++ .../linphone/core/LinphoneAddressImpl.java | 9 +++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 760ce3f29..ca6230b46 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1804,6 +1804,12 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv* return NULL; } } +extern "C" jint Java_org_linphone_core_LinphoneAddressImpl_getTransport(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + LinphoneTransportType transporttype = linphone_address_get_transport((LinphoneAddress*)ptr); + return (jint)transporttype; +} extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toString(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1844,7 +1850,12 @@ extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDomain(JNIEnv* en linphone_address_set_domain((LinphoneAddress*)address,domain); if (domain != NULL) env->ReleaseStringUTFChars(jdomain, domain); } - +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setTransport(JNIEnv* env + ,jobject thiz + ,jlong address + ,jint jtransport) { + linphone_address_set_transport((LinphoneAddress*)address, (LinphoneTransportType) jtransport); +} //CallLog extern "C" jlong Java_org_linphone_core_LinphoneCallLogImpl_getFrom(JNIEnv* env diff --git a/java/common/org/linphone/core/LinphoneAddress.java b/java/common/org/linphone/core/LinphoneAddress.java index fe5164b01..f6c271bd6 100644 --- a/java/common/org/linphone/core/LinphoneAddress.java +++ b/java/common/org/linphone/core/LinphoneAddress.java @@ -17,6 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; + +import java.util.Vector; + /** * Object that represents a SIP address. * The LinphoneAddress is an opaque object to represents SIP addresses, ie the content of SIP's 'from' and 'to' headers. @@ -28,6 +31,38 @@ package org.linphone.core; * */ public interface LinphoneAddress { + static public class TransportType { + static private Vector values = new Vector(); + static public TransportType LinphoneTransportUdp = new TransportType(0, "LinphoneTransportUdp"); + static public TransportType LinphoneTransportTcp = new TransportType(1, "LinphoneTransportTcp"); + static public TransportType LinphoneTransportTls = new TransportType(2, "LinphoneTransportTls"); + + private final int mValue; + private final String mStringValue; + + private TransportType(int value, String stringValue) { + mValue = value; + values.addElement(this); + mStringValue = stringValue; + } + + public static TransportType fromInt(int value) { + for (int i = 0; i < values.size(); i++) { + TransportType type = (TransportType) values.elementAt(i); + if (type.mValue == value) return type; + } + throw new RuntimeException("state not found ["+value+"]"); + } + + public String toString() { + return mStringValue; + } + + public int toInt() { + return mValue; + } + } + /** * Human display name * @return null if not set @@ -99,4 +134,16 @@ public interface LinphoneAddress { * * */ public String toString(); + + /** + * Gets the transport set in the address + * @return the transport + */ + public TransportType getTransport(); + + /** + * Sets the transport in the address + * @param transport the transport to set + */ + public void setTransport(TransportType transport); } diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java index 9eee7ff4f..2d05c720b 100644 --- a/java/impl/org/linphone/core/LinphoneAddressImpl.java +++ b/java/impl/org/linphone/core/LinphoneAddressImpl.java @@ -34,10 +34,12 @@ public class LinphoneAddressImpl implements LinphoneAddress { private native String getDisplayName(long ptr); private native String getUserName(long ptr); private native String getDomain(long ptr); + private native int getTransport(long ptr); private native String toUri(long ptr); private native void setDisplayName(long ptr,String name); private native void setDomain(long ptr,String domain); private native void setUserName(long ptr,String username); + private native void setTransport(long ptr, int transport); private native String toString(long ptr); protected LinphoneAddressImpl(String identity) throws LinphoneCoreException{ @@ -84,6 +86,9 @@ public class LinphoneAddressImpl implements LinphoneAddress { public String getUserName() { return getUserName(nativePtr); } + public TransportType getTransport() { + return TransportType.fromInt(getTransport(nativePtr)); + } public String toString() { return toString(nativePtr); @@ -121,5 +126,7 @@ public class LinphoneAddressImpl implements LinphoneAddress { public void setUserName(String username) { setUserName(nativePtr,username); } - + public void setTransport(TransportType transport) { + setTransport(nativePtr, transport.toInt()); + } } From 9d5c1e7403767e0d3642db8f5d3d7a2e677012dd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Feb 2014 17:29:53 +0100 Subject: [PATCH 252/439] add possibility to set/get subject in SDP --- coreapi/bellesip_sal/sal_sdp.c | 21 ++++------ coreapi/linphonecall.c | 24 +++++++++++ coreapi/linphonecore.h | 4 ++ coreapi/misc.c | 75 ++++++++++++++++++++++++++++++++++ coreapi/private.h | 2 +- gtk/main.c | 1 + include/sal/sal.h | 1 + 7 files changed, 114 insertions(+), 14 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 76d834dab..667c1e22b 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -218,7 +218,8 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr belle_sdp_session_description_set_origin ( session_desc,origin ); - belle_sdp_session_description_set_session_name ( session_desc,belle_sdp_session_name_create ( "Talk" ) ); + belle_sdp_session_description_set_session_name ( session_desc, + belle_sdp_session_name_create ( desc->name[0]!='\0' ? desc->name : "Talk" ) ); if ( (!sal_media_description_has_dir ( desc,SalStreamSendOnly ) && !sal_media_description_has_dir ( desc,SalStreamInactive )) || desc->ice_ufrag[0] != '\0' ) { @@ -251,21 +252,10 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr 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; + belle_sdp_session_name_t *sname; const char *mtype,*proto; SalStreamDescription *stream; belle_sdp_media_t* media; @@ -287,9 +277,14 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S 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 ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){ + strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name)); + } + 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; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index cdf6920c4..c28c83576 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -267,6 +267,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * SalMediaDescription *md=sal_media_description_new(); LinphoneAddress *addr; char* local_ip=call->localip; + const char *subject=linphone_call_params_get_session_name(&call->params); linphone_core_adapt_to_network(lc,call->ping_time,&call->params); @@ -282,6 +283,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * strncpy(md->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); + strncpy(md->name,subject,sizeof(md->name)); if (call->params.down_bw) md->bandwidth=call->params.down_bw; @@ -943,6 +945,7 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ cp->low_bandwidth=TRUE; } } + if (md->name[0]!='\0') linphone_call_params_set_session_name(cp,md->name); } cp->custom_headers=(SalCustomHeader*)sal_op_get_recv_custom_header(call->op); return cp; @@ -1260,10 +1263,31 @@ const char *linphone_call_params_get_custom_header(const LinphoneCallParams *par return sal_custom_header_find(params->custom_headers,header_name); } +/** + * Returns the subject of the media session (ie in SDP). Subject from the SIP message can be retrieved using linphone_call_params_get_custom_header(). + * @param cp the call parameters. +**/ +const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp){ + return cp->subject; +} + +/** + * Set the subject of the media session (ie in SDP). Subject from the SIP message can be set using linphone_call_params_set_custom_header(). + * @param cp the call parameters. +**/ +void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *subject){ + if (cp->subject){ + ms_free(cp->subject); + cp->subject=NULL; + } + if (subject) cp->subject=ms_strdup(subject); +} + 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); + if (cp->subject) ncp->subject=ms_strdup(cp->subject); /* * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. */ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index aec4df508..7d3bee804 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -371,6 +371,8 @@ LINPHONE_PUBLIC bool_t linphone_call_params_low_bandwidth_enabled(const Linphone LINPHONE_PUBLIC void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled); LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path); LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp); +LINPHONE_PUBLIC const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp); +LINPHONE_PUBLIC void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *subject); /** * Add a custom SIP header in the INVITE for a call. @@ -2302,6 +2304,8 @@ LINPHONE_PUBLIC void linphone_core_set_provisioning_uri(LinphoneCore *lc, const **/ LINPHONE_PUBLIC const char* linphone_core_get_provisioning_uri(const LinphoneCore *lc); + +LINPHONE_PUBLIC int linphone_core_migrate_to_multi_transport(LinphoneCore *lc); #ifdef __cplusplus } #endif diff --git a/coreapi/misc.c b/coreapi/misc.c index 3a93bf97e..c64d51160 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1200,4 +1200,79 @@ void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun belle_sip_object_unref(s); } +static int get_unique_transport(LinphoneCore *lc, LinphoneTransportType *type, int *port){ + LCSipTransports tp; + linphone_core_get_sip_transports(lc,&tp); + if (tp.tcp_port==0 && tp.tls_port==0 && tp.udp_port!=0){ + *type=LinphoneTransportUdp; + *port=tp.udp_port; + return 0; + }else if (tp.tcp_port==0 && tp.udp_port==0 && tp.tls_port!=0){ + *type=LinphoneTransportTls; + *port=tp.tls_port; + return 0; + }else if (tp.tcp_port!=0 && tp.udp_port==0 && tp.tls_port==0){ + *type=LinphoneTransportTcp; + *port=tp.tcp_port; + return 0; + } + return -1; +} + +static void linphone_core_migrate_proxy_config(LinphoneCore *lc, LinphoneTransportType type){ + const MSList *elem; + for(elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; + const char *proxy=linphone_proxy_config_get_addr(cfg); + const char *route=linphone_proxy_config_get_route(cfg); + LinphoneAddress *proxy_addr=linphone_address_new(proxy); + LinphoneAddress *route_addr=NULL; + char *tmp; + if (route) route_addr=linphone_address_new(route); + if (proxy_addr){ + linphone_address_set_transport(proxy_addr,type); + tmp=linphone_address_as_string(proxy_addr); + linphone_proxy_config_set_server_addr(cfg,tmp); + ms_free(tmp); + linphone_address_destroy(proxy_addr); + } + if (route_addr){ + linphone_address_set_transport(route_addr,type); + tmp=linphone_address_as_string(route_addr); + linphone_proxy_config_set_route(cfg,tmp); + ms_free(tmp); + linphone_address_destroy(route_addr); + } + } +} + +/** + * Migrate configuration so that all SIP transports are enabled. + * Versions of linphone < 3.7 did not support using multiple SIP transport simultaneously. + * This function helps application to migrate the configuration so that all transports are enabled. + * Existing proxy configuration are added a transport parameter so that they continue using the unique transport that was set previously. + * This function must be used just after creating the core, before any call to linphone_core_iterate() + * @param lc the linphone core + * @returns 1 if migration was done, 0 if not done because unnecessary or already done, -1 in case of error. + * @ingroup initializing +**/ +int linphone_core_migrate_to_multi_transport(LinphoneCore *lc){ + if (!lp_config_get_int(lc->config,"sip","multi_transport_migration_done",0)){ + LinphoneTransportType tpt; + int port; + if (get_unique_transport(lc,&tpt,&port)==0){ + LCSipTransports newtp={0}; + ms_message("Core is using a single SIP transport, migrating proxy config and enabling multi-transport."); + linphone_core_migrate_proxy_config(lc,tpt); + newtp.udp_port=port; + newtp.tcp_port=port; + newtp.tls_port=LC_SIP_TRANSPORT_RANDOM; + linphone_core_set_sip_transports(lc,&newtp); + } + lp_config_set_int(lc->config,"sip","multi_transport_migration_done",1); + return 1; + } + return 0; +} + diff --git a/coreapi/private.h b/coreapi/private.h index 1c9c8e5a1..7ba09d33b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -91,11 +91,11 @@ struct _LinphoneCallParams{ int down_ptime; int up_ptime; char *record_file; + char *subject; SalCustomHeader *custom_headers; bool_t has_video; bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/ bool_t in_conference; /*in conference mode */ - bool_t pad; bool_t low_bandwidth; LinphonePrivacyMask privacy; }; diff --git a/gtk/main.c b/gtk/main.c index 307dc7f51..9f897eb1d 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -286,6 +286,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.configuring_status=linphone_gtk_configuring_status; the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); + linphone_core_migrate_to_multi_transport(the_core); //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); diff --git a/include/sal/sal.h b/include/sal/sal.h index 644649d13..87092cfad 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -203,6 +203,7 @@ typedef struct SalStreamDescription{ typedef struct SalMediaDescription{ int refcount; + char name[64]; char addr[64]; char username[64]; int n_active_streams; From 6acb64ac5bf8fffc9c26fa46be68c8c503896bc0 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 18 Feb 2014 17:35:48 +0100 Subject: [PATCH 253/439] Store calllogs instead of linphoneAddress --- gtk/calllogs.c | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/gtk/calllogs.c b/gtk/calllogs.c index e9b460636..2f7e8f769 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -56,11 +56,13 @@ void linphone_gtk_call_log_chat_selected(GtkWidget *w){ if (select!=NULL){ GtkTreeModel *model=NULL; if (gtk_tree_selection_get_selected (select,&model,&iter)){ - gpointer pla; + gpointer pcl; LinphoneAddress *la; - gtk_tree_model_get(model,&iter,2,&pla,-1); - la=(LinphoneAddress*)pla; - if (la!=NULL){ + LinphoneCallLog *cl; + gtk_tree_model_get(model,&iter,2,&pcl,-1); + cl = (LinphoneCallLog *)pcl; + la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + if (la != NULL){ linphone_gtk_friend_list_set_chat_conversation(la); } } @@ -75,12 +77,14 @@ void linphone_gtk_call_log_add_contact(GtkWidget *w){ if (select!=NULL){ GtkTreeModel *model=NULL; if (gtk_tree_selection_get_selected (select,&model,&iter)){ - gpointer pla; + gpointer pcl; LinphoneAddress *la; + LinphoneCallLog *cl; LinphoneFriend *lf; - gtk_tree_model_get(model,&iter,2,&pla,-1); - la=(LinphoneAddress*)pla; - if (la!=NULL){ + gtk_tree_model_get(model,&iter,2,&pcl,-1); + cl = (LinphoneCallLog *)pcl; + la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + if (la != NULL){ char *uri=linphone_address_as_string(la); lf=linphone_friend_new_with_address(uri); linphone_gtk_show_contact(lf); @@ -92,16 +96,19 @@ void linphone_gtk_call_log_add_contact(GtkWidget *w){ static bool_t put_selection_to_uribar(GtkWidget *treeview){ GtkTreeSelection *sel; - sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); if (sel!=NULL){ GtkTreeModel *model=NULL; GtkTreeIter iter; if (gtk_tree_selection_get_selected (sel,&model,&iter)){ char *tmp; + gpointer pcl; LinphoneAddress *la; - gtk_tree_model_get(model,&iter,2,&la,-1); - tmp=linphone_address_as_string(la); + LinphoneCallLog *cl; + gtk_tree_model_get(model,&iter,2,&pcl,-1); + cl = (LinphoneCallLog *)pcl; + la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + tmp = linphone_address_as_string(la); if(tmp!=NULL) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),tmp); ms_free(tmp); @@ -131,10 +138,12 @@ static GtkWidget *linphone_gtk_create_call_log_menu(GtkWidget *call_log){ if (select!=NULL){ GtkTreeModel *model=NULL; if (gtk_tree_selection_get_selected (select,&model,&iter)){ - gpointer pla; + gpointer pcl; LinphoneAddress *la; - gtk_tree_model_get(model,&iter,2,&pla,-1); - la=(LinphoneAddress*)pla; + LinphoneCallLog *cl; + gtk_tree_model_get(model,&iter,2,&pcl,-1); + cl = (LinphoneCallLog *)pcl; + la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); name=linphone_address_as_string(la); call_label=g_strdup_printf(_("Call %s"),name); text_label=g_strdup_printf(_("Send text to %s"),name); @@ -262,7 +271,7 @@ void linphone_gtk_call_log_update(GtkWidget *w){ for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){ LinphoneCallLog *cl=(LinphoneCallLog*)logs->data; GtkTreeIter iter, iter2; - const LinphoneAddress *la=linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); + LinphoneAddress *la=linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl); char *addr= linphone_address_as_string(la); const char *display; gchar *logtxt, *headtxt, *minutes, *seconds; @@ -284,8 +293,7 @@ void linphone_gtk_call_log_update(GtkWidget *w){ #endif lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),addr); if(lf != NULL){ - la=linphone_friend_get_address(lf); - display=linphone_address_get_display_name(la); + display=linphone_address_get_display_name(linphone_friend_get_address(lf)); } else { display=linphone_address_get_display_name(la); } @@ -294,6 +302,8 @@ void linphone_gtk_call_log_update(GtkWidget *w){ if (display==NULL){ display=linphone_address_get_domain (la); } + } else { + linphone_address_set_display_name(la,display); } if (linphone_call_log_get_quality(cl)!=-1){ snprintf(quality,sizeof(quality),"%.1f",linphone_call_log_get_quality(cl)); @@ -338,9 +348,9 @@ void linphone_gtk_call_log_update(GtkWidget *w){ GdkPixbuf *outgoing = create_pixbuf("call_status_outgoing.png"); gtk_tree_store_set (store,&iter, 0, linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? outgoing : incoming, - 1, headtxt,2,la,-1); + 1, headtxt,2,cl,-1); gtk_tree_store_append (store,&iter2,&iter); - gtk_tree_store_set (store,&iter2,1,logtxt,2,la,-1); + gtk_tree_store_set (store,&iter2,1,logtxt,-1); ms_free(addr); g_free(logtxt); g_free(headtxt); @@ -398,4 +408,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 +} From bfd8151dcfd379266fc83c3de15937254111e9c3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 18 Feb 2014 22:10:13 +0100 Subject: [PATCH 254/439] add java wrapper for linphone_call_params_set/get_session_name() --- coreapi/linphonecore_jni.cc | 17 +++++++++++++++++ .../org/linphone/core/LinphoneCallParams.java | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index ca6230b46..e80c85dea 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2583,6 +2583,23 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setPrivacy(JNIEnv* linphone_call_params_set_privacy((LinphoneCallParams*)cp,privacy); } +extern "C" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getSessionName(JNIEnv* env + ,jobject thiz + ,jlong cp + ) { + const char* name = linphone_call_params_get_session_name((LinphoneCallParams*)cp); + return name ? env->NewStringUTF(name) : NULL; +} + +extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setSessionName(JNIEnv* env + ,jobject thiz + ,jlong cp + ,jstring jname) { + const char *name = jname ? env->GetStringUTFChars(jname,NULL) : NULL; + linphone_call_params_set_session_name((LinphoneCallParams*)cp,name); + if (name) env->ReleaseStringUTFChars(jname,name); +} + extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_audioBandwidth(JNIEnv *env, jobject thiz, jlong lcp, jint bw){ linphone_call_params_set_audio_bandwidth_limit((LinphoneCallParams*)lcp, bw); } diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java index 530cf63b9..86dd1ea4b 100644 --- a/java/common/org/linphone/core/LinphoneCallParams.java +++ b/java/common/org/linphone/core/LinphoneCallParams.java @@ -105,4 +105,15 @@ public interface LinphoneCallParams { * @return the privacy mask as defined in interface {@link org.linphone.core.Privacy} */ int getPrivacy(); + + /** + * Set the session name of the media session (ie in SDP). Subject from the SIP message can be retrieved using linphone_call_params_get_custom_header(). + * @param name the session name + **/ + void setSessionName(String name); + /** + * Get the session name of the media session (ie in SDP). Subject from the SIP message can be retrieved using linphone_call_params_get_custom_header(). + * @return the session name + **/ + String getSessionName(); } From b57f8b1526e3ea128480a9672e84215c6fbc26cc Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 18 Feb 2014 15:55:56 +0100 Subject: [PATCH 255/439] Added 302 redirection support. + removed macros for sal_op_get_contact compatibility --- coreapi/bellesip_sal/sal_impl.c | 10 ++++ coreapi/bellesip_sal/sal_op_call.c | 2 +- coreapi/bellesip_sal/sal_op_impl.c | 10 +++- coreapi/bellesip_sal/sal_op_message.c | 2 +- coreapi/bellesip_sal/sal_op_publish.c | 4 +- coreapi/callbacks.c | 20 ++++++- coreapi/linphonecall.c | 23 ++++++-- coreapi/linphonecore.c | 32 +++++----- coreapi/linphonecore.h | 1 + coreapi/presence.c | 4 +- coreapi/private.h | 2 +- coreapi/proxy.c | 4 +- coreapi/sal.c | 32 +++++----- include/sal/sal.h | 6 +- tester/call_tester.c | 84 ++++++++++++++++++++++++--- 15 files changed, 171 insertions(+), 65 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 70f04673c..eacc38686 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -198,6 +198,7 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve belle_sip_response_t* resp; belle_sip_header_t *evh; const char *method=belle_sip_request_get_method(req); + belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t); from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); @@ -257,6 +258,9 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve belle_sip_object_unref(address); } + if( remote_contact ){ + __sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); + } if (!op->base.to_address) { to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); @@ -303,6 +307,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } else { SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(response, belle_sip_header_contact_t); if (op->state == SalOpStateTerminated) { belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); @@ -311,6 +316,11 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even if (!op->base.remote_ua) { sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); } + + if(remote_contact) { + __sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); + } + if (!op->base.call_id) { op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(response), belle_sip_header_call_id_t)))); } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 7fe5982c7..a51792706 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -725,7 +725,7 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti if (reason==SalReasonRedirect){ if (redirection!=NULL) { if (strstr(redirection,"sip:")!=0) status=302; - status=380; + else status=380; contact= belle_sip_header_contact_new(); belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection)); } else { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index cade07854..e1b5d7a0b 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -210,7 +210,7 @@ static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *m if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){ belle_sip_header_contact_t* newct; /*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/ - sal_op_set_contact(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h)); + sal_op_set_contact_address(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h)); newct = sal_op_create_contact(op); belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct)); return; @@ -381,6 +381,10 @@ SalReason sal_reason_to_sip_code(SalReason r){ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { switch(code) { + case 302: + *sal_reason=SalReasonRedirect; + *sal_err=SalErrorFailure; + break; case 400: *sal_err=SalErrorUnknown; break; @@ -560,7 +564,9 @@ void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){ } const char *sal_op_get_remote_contact(const SalOp *op){ - return sal_custom_header_find(op->base.recv_custom_headers,"Contact"); + // remote contact is filled in process_response +// return sal_custom_header_find(op->base.recv_custom_headers,"Contact"); + return op->base.remote_contact; } void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body){ diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 0db775a3c..c147b649b 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -162,7 +162,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co op->dir=SalOpDirOutgoing; req=sal_op_build_request(op,"MESSAGE"); - if (sal_op_get_contact(op)){ + if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 196167095..a55042919 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -72,7 +72,7 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expire op->type=SalOpPublish; req=sal_op_build_request(op,"PUBLISH"); - if (sal_op_get_contact(op)){ + if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence")); @@ -97,7 +97,7 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna sal_op_publish_fill_cbs(op); req=sal_op_build_request(op,"PUBLISH"); - if (sal_op_get_contact(op)){ + if (sal_op_get_contact_address(op)){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op))); } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 2a98769e7..a31ac04d7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -76,7 +76,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia SalMediaDescription *oldmd=call->resultdesc; bool_t all_muted=FALSE; bool_t send_ringbacktone=FALSE; - + linphone_core_stop_ringing(lc); if (!new_md) { ms_error("linphone_core_update_streams() called with null media description"); @@ -620,9 +620,27 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de lc->vtable.display_status(lc,msg486); break; case SalReasonRedirect: + { + ms_error("case SalReasonRedirect"); + linphone_call_stop_media_streams(call); + if ( call->state==LinphoneCallOutgoingInit + || call->state==LinphoneCallOutgoingProgress + || call->state==LinphoneCallOutgoingRinging /*push case*/ + || call->state==LinphoneCallOutgoingEarlyMedia){ + LinphoneAddress* redirection_to = linphone_call_get_remote_contact_address(call); + if( redirection_to ){ + char* url = linphone_address_as_string(redirection_to); + ms_error("Redirecting call [%p] to %s",call, url); + ms_free(url); + linphone_call_create_op(call); + linphone_core_start_invite(lc, call, redirection_to); + return; + } + } msg=_("Redirected"); if (lc->vtable.display_status) lc->vtable.display_status(lc,msg); + } break; case SalReasonTemporarilyUnavailable: msg=msg480; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c28c83576..bbae572d4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1064,6 +1064,17 @@ const char *linphone_call_get_remote_contact(LinphoneCall *call){ return NULL; } +/** + * Returns the far end's sip contact as a string, if available. +**/ +LinphoneAddress *linphone_call_get_remote_contact_address(LinphoneCall *call){ + if (call->op){ + return (LinphoneAddress*)sal_op_get_remote_contact_address(call->op); + } + return NULL; +} + + /** * Returns true if this calls has received a transfer that has not been * executed yet. @@ -2792,18 +2803,18 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , ctt=linphone_core_get_primary_contact_parsed(lc); linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc)); ret=ctt; - } else if (call->op && sal_op_get_contact(call->op)!=NULL){ + } else if (call->op && sal_op_get_contact_address(call->op)!=NULL){ /* if already choosed, don't change it */ return NULL; - } else if (call->ping_op && sal_op_get_contact(call->ping_op)) { + } else if (call->ping_op && sal_op_get_contact_address(call->ping_op)) { /* if the ping OPTIONS request succeeded use the contact guessed from the received, rport*/ ms_message("Contact has been fixed using OPTIONS"/* to %s",guessed*/); - ret=linphone_address_clone(sal_op_get_contact(call->ping_op));; - } else if (dest_proxy && dest_proxy->op && sal_op_get_contact(dest_proxy->op)){ + ret=linphone_address_clone(sal_op_get_contact_address(call->ping_op));; + } else if (dest_proxy && dest_proxy->op && sal_op_get_contact_address(dest_proxy->op)){ /*if using a proxy, use the contact address as guessed with the REGISTERs*/ ms_message("Contact has been fixed using proxy" /*to %s",fixed_contact*/); - ret=linphone_address_clone(sal_op_get_contact(dest_proxy->op)); + ret=linphone_address_clone(sal_op_get_contact_address(dest_proxy->op)); } else { ctt=linphone_core_get_primary_contact_parsed(lc); if (ctt!=NULL){ @@ -2832,7 +2843,7 @@ void linphone_call_set_contact_op(LinphoneCall* call) { 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); + sal_op_set_contact_address(call->op, contact); linphone_address_destroy(contact); } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b20ea9c8f..812565ac9 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2265,7 +2265,7 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_call_delete_upnp_session(call); } #endif //BUILD_UPNP - linphone_core_start_invite(lc,call); + linphone_core_start_invite(lc,call, NULL); } if (call->state==LinphoneCallIncomingReceived){ if (one_second_elapsed) ms_message("incoming call ringing for %i seconds",elapsed); @@ -2572,17 +2572,17 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c } if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) { - return linphone_core_start_invite(lc, call); + return linphone_core_start_invite(lc, call, NULL); } return 0; } int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){ linphone_call_create_op(call); - return linphone_core_start_invite(lc,call); + return linphone_core_start_invite(lc,call, NULL); } -int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ +int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const LinphoneAddress* destination /* = NULL if to be taken from the call log */){ int err; char *real_url,*barmsg; char *from; @@ -2592,7 +2592,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ linphone_core_stop_dtmf_stream(lc); linphone_call_init_media_streams(call); linphone_call_make_local_media_description(lc,call); - + if (lc->ringstream==NULL) { if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard){ /*give a chance a set card prefered sampling frequency*/ @@ -2602,20 +2602,20 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } } - real_url=linphone_address_as_string(call->log->to); + real_url=linphone_address_as_string( destination ? destination : call->log->to); from=linphone_address_as_string(call->log->from); - + if (!lc->sip_conf.sdp_200_ack){ /*we are offering, set local media description before sending the call*/ sal_call_set_local_media_description(call->op,call->localdesc); } err=sal_call(call->op,from,real_url); if (lc->sip_conf.sdp_200_ack){ - /*we are NOT offering, set local media description after sending the call so that we are ready to + /*we are NOT offering, set local media description after sending the call so that we are ready to process the remote offer when it will arrive*/ sal_call_set_local_media_description(call->op,call->localdesc); } - + call->log->call_id=ms_strdup(sal_op_get_call_id(call->op)); /*must be known at that time*/ barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); @@ -2735,12 +2735,12 @@ void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *d sal_op_set_sent_custom_header(op,headers); if (with_contact && proxy && proxy->op){ const SalAddress *contact; - if ((contact=sal_op_get_contact(proxy->op))){ + if ((contact=sal_op_get_contact_address(proxy->op))){ SalTransport tport=sal_address_get_transport((SalAddress*)contact); SalAddress *new_contact=sal_address_clone(contact); sal_address_clean(new_contact); /* clean out contact_params that come from proxy config*/ sal_address_set_transport(new_contact,tport); - sal_op_set_contact(op,new_contact); + sal_op_set_contact_address(op,new_contact); sal_address_destroy(new_contact); } } @@ -2791,14 +2791,14 @@ 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,proxy); - + if(linphone_core_add_call(lc,call)!= 0) { ms_warning("we had a problem in adding the call into the invite ... weird"); linphone_call_unref(call); return NULL; } - + /* this call becomes now the current one*/ lc->current_call=call; linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); @@ -2845,7 +2845,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const } } - if (defer==FALSE) linphone_core_start_invite(lc,call); + if (defer==FALSE) linphone_core_start_invite(lc,call,NULL); if (real_url!=NULL) ms_free(real_url); return call; @@ -3033,8 +3033,8 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ 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); + sal_op_set_contact_address(call->op,sal_op_get_contact_address(call->dest_proxy->op)); + }else sal_op_set_contact_address(call->op,NULL); return sal_call_update(call->op,subject); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7d3bee804..291748312 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -655,6 +655,7 @@ LINPHONE_PUBLIC int linphone_call_take_video_snapshot(LinphoneCall *call, const LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call); LINPHONE_PUBLIC const char *linphone_call_get_remote_user_agent(LinphoneCall *call); LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call); +LINPHONE_PUBLIC LinphoneAddress *linphone_call_get_remote_contact_address(LinphoneCall *call); LINPHONE_PUBLIC float linphone_call_get_play_volume(LinphoneCall *call); LINPHONE_PUBLIC float linphone_call_get_record_volume(LinphoneCall *call); LINPHONE_PUBLIC float linphone_call_get_current_quality(LinphoneCall *call); diff --git a/coreapi/presence.c b/coreapi/presence.c index 668d8ad4b..af4c5184d 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1476,8 +1476,8 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ cfg=linphone_core_lookup_known_proxy(lc,uri); if (cfg!=NULL){ if (cfg->op){ - if (sal_op_get_contact(cfg->op)) { - sal_op_set_contact (op,sal_op_get_contact(cfg->op)); + if (sal_op_get_contact_address(cfg->op)) { + sal_op_set_contact_address (op,sal_op_get_contact_address(cfg->op)); ms_message("Contact for next subscribe answer has been fixed using proxy "/*to %s",fixed_contact*/); } } diff --git a/coreapi/private.h b/coreapi/private.h index 7ba09d33b..948bac604 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -368,7 +368,7 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float void linphone_core_stop_waiting(LinphoneCore *lc); int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy); -int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call); +int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const LinphoneAddress* destination/* = NULL if to be taken from the call log */); int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call); int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 0c710cb3a..6bc8e5588 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -329,7 +329,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ 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); + sal_op_set_contact_address(obj->op,contact); linphone_address_destroy(contact); } sal_op_set_user_pointer(obj->op,obj); @@ -815,7 +815,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePrese sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); if (lp_config_get_int(proxy->lc->config,"sip","publish_msg_with_contact",0)){ SalAddress *addr=sal_address_new(linphone_proxy_config_get_identity(proxy)); - sal_op_set_contact(proxy->publish_op,addr); + sal_op_set_contact_address(proxy->publish_op,addr); sal_address_unref(addr); } } diff --git a/coreapi/sal.c b/coreapi/sal.c index de5f235df..46f7325df 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -253,7 +253,6 @@ static void assign_string(char **str, const char *arg){ *str=ms_strdup(arg); } -#ifdef USE_BELLESIP void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ if (((SalOpBase*)op)->contact_address) sal_address_destroy(((SalOpBase*)op)->contact_address); ((SalOpBase*)op)->contact_address=address?sal_address_clone(address):NULL; @@ -261,7 +260,12 @@ void sal_op_set_contact_address(SalOp *op, const SalAddress *address){ const SalAddress* sal_op_get_contact_address(const SalOp *op) { return ((SalOpBase*)op)->contact_address; } -#endif + +const SalAddress*sal_op_get_remote_contact_address(const SalOp* op) +{ + return ((SalOpBase*)op)->remote_contact_address; +} + #define SET_PARAM(op,name) \ char* name##_string=NULL; \ assign_address(&((SalOpBase*)op)->name##_address,name); \ @@ -271,14 +275,7 @@ const SalAddress* sal_op_get_contact_address(const SalOp *op) { assign_string(&((SalOpBase*)op)->name,name##_string); \ if(name##_string) ms_free(name##_string); -#ifndef USE_BELLESIP -void sal_op_set_contact(SalOp *op, const char *contact){ - assign_string(&((SalOpBase*)op)->contact,contact); -} -const char *sal_op_get_contact(const SalOp *op){ - return ((SalOpBase*)op)->contact; -} -#endif + void sal_op_set_route(SalOp *op, const char *route){ char* route_string=(void *)0; SalOpBase* op_base = (SalOpBase*)op; @@ -384,9 +381,10 @@ void __sal_op_set_network_origin(SalOp *op, const char *origin){ SET_PARAM(op,origin); } -void __sal_op_set_remote_contact(SalOp *op, const char *ct){ - assign_string(&((SalOpBase*)op)->remote_contact,ct); +void __sal_op_set_remote_contact(SalOp *op, const char* remote_contact){ + SET_PARAM(op,remote_contact); } + void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin){ char* address_string=sal_address_as_string(origin); /*can probably be optimized*/ __sal_op_set_network_origin(op,address_string); @@ -426,16 +424,9 @@ void __sal_op_free(SalOp *op){ ms_free(b->route); b->route=NULL; } -#ifndef USE_BELLESIP - if (b->contact) { - ms_free(b->contact); - b->contact=NULL; - } -#else if (b->contact_address) { sal_address_destroy(b->contact_address); } -#endif if (b->origin){ ms_free(b->origin); b->origin=NULL; @@ -448,6 +439,9 @@ void __sal_op_free(SalOp *op){ ms_free(b->remote_contact); b->remote_contact=NULL; } + if (b->remote_contact_address){ + sal_address_destroy(b->remote_contact_address); + } if (b->local_media) sal_media_description_unref(b->local_media); if (b->remote_media) diff --git a/include/sal/sal.h b/include/sal/sal.h index 87092cfad..8ff57dc12 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -256,11 +256,12 @@ typedef struct SalOpBase{ char *origin; SalAddress* origin_address; char *remote_ua; + SalAddress* remote_contact_address; + char *remote_contact; SalMediaDescription *local_media; SalMediaDescription *remote_media; void *user_pointer; const char* call_id; - char *remote_contact; SalAddress* service_route; /*as defined by rfc3608, might be a list*/ SalCustomHeader *sent_custom_headers; SalCustomHeader *recv_custom_headers; @@ -517,7 +518,6 @@ SalOp * sal_op_new(Sal *sal); /*generic SalOp API, working for all operations */ Sal *sal_op_get_sal(const SalOp *op); -#define sal_op_set_contact sal_op_set_contact_address /*for liblinphone compatibility*/ 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); @@ -537,11 +537,11 @@ 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 SalAddress *sal_op_get_contact_address(const SalOp *op); -#define sal_op_get_contact sal_op_get_contact_address /*for liblinphone compatibility*/ const char *sal_op_get_route(const SalOp *op); const MSList* sal_op_get_route_addresses(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); const char *sal_op_get_remote_contact(const SalOp *op); +const SalAddress* sal_op_get_remote_contact_address(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); diff --git a/tester/call_tester.c b/tester/call_tester.c index ecf0068bf..2b40e6bf0 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -548,10 +548,15 @@ static void call_with_ice(void) { static void call_with_custom_headers(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCall *c1,*c2; + LinphoneCall *call_marie,*call_pauline; LinphoneCallParams *params; const LinphoneCallParams *remote_params; const char *hvalue; + const char *pauline_remote_contact_header, + *pauline_remote_contact, + *marie_remote_contact, + *marie_remote_contact_header; + char* tmp=linphone_address_as_string_uri_only(marie->identity); char tmp2[256]; snprintf(tmp2,sizeof(tmp2),"%s?uriHeader=myUriHeader",tmp); @@ -567,13 +572,13 @@ static void call_with_custom_headers(void) { CU_ASSERT_TRUE(call_with_caller_params(pauline,marie,params)); linphone_call_params_destroy(params); - c1=linphone_core_get_current_call(marie->lc); - c2=linphone_core_get_current_call(pauline->lc); + call_marie=linphone_core_get_current_call(marie->lc); + call_pauline=linphone_core_get_current_call(pauline->lc); - CU_ASSERT_PTR_NOT_NULL(c1); - CU_ASSERT_PTR_NOT_NULL(c2); + CU_ASSERT_PTR_NOT_NULL(call_marie); + CU_ASSERT_PTR_NOT_NULL(call_pauline); - remote_params=linphone_call_get_remote_params(c1); + remote_params=linphone_call_get_remote_params(call_marie); hvalue=linphone_call_params_get_custom_header(remote_params,"Weather"); CU_ASSERT_PTR_NOT_NULL(hvalue); CU_ASSERT_STRING_EQUAL(hvalue,"bad"); @@ -581,8 +586,18 @@ static void call_with_custom_headers(void) { CU_ASSERT_PTR_NOT_NULL(hvalue); CU_ASSERT_STRING_EQUAL(hvalue,"myUriHeader"); - CU_ASSERT_PTR_NOT_NULL(linphone_call_get_remote_contact(c1)); - + + pauline_remote_contact_header = linphone_call_params_get_custom_header(linphone_call_get_remote_params(call_pauline), "Contact"); + pauline_remote_contact = linphone_call_get_remote_contact(call_pauline); + marie_remote_contact = linphone_call_get_remote_contact(call_marie); + marie_remote_contact_header = linphone_call_params_get_custom_header(remote_params, "Contact"); + CU_ASSERT_PTR_NOT_NULL(pauline_remote_contact); + CU_ASSERT_PTR_NOT_NULL(pauline_remote_contact_header); + CU_ASSERT_PTR_NOT_NULL(marie_remote_contact); + CU_ASSERT_PTR_NOT_NULL(marie_remote_contact_header); + CU_ASSERT_STRING_EQUAL(pauline_remote_contact,pauline_remote_contact_header); + CU_ASSERT_STRING_EQUAL(marie_remote_contact,marie_remote_contact_header); + /*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)); @@ -1377,6 +1392,56 @@ static void call_established_with_rejected_incoming_reinvite(void) { linphone_core_manager_destroy(pauline); } +static void call_redirect(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"); + MSList* lcs = NULL; + char *margaux_url = NULL; + LinphoneCall* marie_call; + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + lcs = ms_list_append(lcs,laure->lc); + /* + Marie calls Pauline, which will redirect the call to Laure via a 302 + */ + + marie_call = linphone_core_invite_address(marie->lc, pauline->identity); + + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + + margaux_url = linphone_address_as_string(laure->identity); + linphone_core_redirect_call(pauline->lc, linphone_core_get_current_call(pauline->lc), margaux_url); + ms_free(margaux_url); + + /* laure should be ringing now */ + CU_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallIncomingReceived,1,6000)); + /* pauline should have ended the call */ + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallEnd,1,1000)); + /* the call should still be ringing on marie's side */ + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1,1000)); + + linphone_core_accept_call(laure->lc, linphone_core_get_current_call(laure->lc)); + + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + + CU_ASSERT_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); + + liblinphone_tester_check_rtcp(marie, laure); + + linphone_core_terminate_all_calls(laure->lc); + + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + +} + 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"); @@ -1503,7 +1568,8 @@ test_t call_tests[] = { { "Call established with rejected INFO",call_established_with_rejected_info}, { "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite}, { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, - { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error} + { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, + { "Call redirected by callee", call_redirect} }; test_suite_t call_test_suite = { From c7f8b5aae42672db95fcef850c88b1a1ee3ca96f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 19 Feb 2014 11:04:25 +0100 Subject: [PATCH 256/439] fix previous commit --- .../org/linphone/core/LinphoneCallParamsImpl.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java index aaafe9186..9c3fe9468 100644 --- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java @@ -118,5 +118,17 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams { public int getPrivacy() { return getPrivacy(nativePtr); } + + private native void setSessionName(long nativePtr, String name); + @Override + public void setSessionName(String name) { + setSessionName(nativePtr,name); + } + + private native String getSessionName(long nativePtr); + @Override + public String getSessionName() { + return getSessionName(nativePtr); + } } From 7e436c72608add66760272f8d0daf8a6291528d7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 19 Feb 2014 11:46:48 +0100 Subject: [PATCH 257/439] Updated ms2 + added wrapped migration to multi transport method in JNI --- coreapi/linphonecore_jni.cc | 6 ++++++ java/common/org/linphone/core/LinphoneCore.java | 10 ++++++++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 8 ++++++++ mediastreamer2 | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index e80c85dea..340210805 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -779,6 +779,12 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env delete lcData; } +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_migrateToMultiTransport(JNIEnv* env + ,jobject thiz + ,jlong lc) { + return (jint) linphone_core_migrate_to_multi_transport((LinphoneCore *)lc); +} + /* * Class: org_linphone_core_LinphoneCoreImpl * Method: createInfoMessage diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 6c7094ddf..114150acf 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1463,4 +1463,14 @@ public interface LinphoneCore { * @return an array of String */ public String[] getSupportedVideoSizes(); + + /** + * Migrate configuration so that all SIP transports are enabled. + * Versions of linphone < 3.7 did not support using multiple SIP transport simultaneously. + * This function helps application to migrate the configuration so that all transports are enabled. + * Existing proxy configuration are added a transport parameter so that they continue using the unique transport that was set previously. + * This function must be used just after creating the core, before any call to linphone_core_iterate() + * @returns 1 if migration was done, 0 if not done because unnecessary or already done, -1 in case of error. + */ + public int migrateToMultiTransport(); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index bdb3540aa..d3803df22 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -144,6 +144,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native String getPrimaryContactDisplayName(long nativePtr); private native void setChatDatabasePath(long nativePtr, String path); private native long[] getChatRooms(long nativePtr); + private native int migrateToMultiTransport(long nativePtr); LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata) throws IOException { mListener = listener; @@ -396,10 +397,12 @@ class LinphoneCoreImpl implements LinphoneCore { addFriend(nativePtr,((LinphoneFriendImpl)lf).nativePtr); } + @SuppressWarnings("deprecation") public synchronized void setPresenceInfo(int minutes_away, String alternative_contact, OnlineStatus status) { setPresenceInfo(nativePtr,minutes_away,alternative_contact,status.mValue); } + @SuppressWarnings("deprecation") public synchronized OnlineStatus getPresenceInfo() { return OnlineStatus.fromInt(getPresenceInfo(nativePtr)); } @@ -1094,4 +1097,9 @@ class LinphoneCoreImpl implements LinphoneCore { public String[] getSupportedVideoSizes() { return listSupportedVideoResolutions(nativePtr); } + + @Override + public int migrateToMultiTransport() { + return migrateToMultiTransport(nativePtr); + } } diff --git a/mediastreamer2 b/mediastreamer2 index c4fd2eea1..1de47782b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c4fd2eea1e49cb102327670a122a177e08a7f206 +Subproject commit 1de47782b0598594d8c6c55e9ff641da51326719 From 7330cae8a2e5289360fff9035528da7ff74146cb Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 19 Feb 2014 11:49:57 +0100 Subject: [PATCH 258/439] fix crash --- coreapi/linphonecall.c | 21 +++++++++++---------- coreapi/private.h | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index bbae572d4..901fcf5be 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -283,7 +283,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * strncpy(md->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); - strncpy(md->name,subject,sizeof(md->name)); + if (subject) strncpy(md->name,subject,sizeof(md->name)); if (call->params.down_bw) md->bandwidth=call->params.down_bw; @@ -1275,30 +1275,31 @@ const char *linphone_call_params_get_custom_header(const LinphoneCallParams *par } /** - * Returns the subject of the media session (ie in SDP). Subject from the SIP message can be retrieved using linphone_call_params_get_custom_header(). + * Returns the session name of the media session (ie in SDP). Subject from the SIP message can be retrieved using linphone_call_params_get_custom_header() and is different. * @param cp the call parameters. **/ const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp){ - return cp->subject; + return cp->session_name; } /** - * Set the subject of the media session (ie in SDP). Subject from the SIP message can be set using linphone_call_params_set_custom_header(). + * Set the session name of the media session (ie in SDP). Subject from the SIP message (which is different) can be set using linphone_call_params_set_custom_header(). * @param cp the call parameters. + * @param name the session name **/ -void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *subject){ - if (cp->subject){ - ms_free(cp->subject); - cp->subject=NULL; +void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *name){ + if (cp->session_name){ + ms_free(cp->session_name); + cp->session_name=NULL; } - if (subject) cp->subject=ms_strdup(subject); + if (name) cp->session_name=ms_strdup(name); } 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); - if (cp->subject) ncp->subject=ms_strdup(cp->subject); + if (cp->session_name) ncp->session_name=ms_strdup(cp->session_name); /* * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient. */ diff --git a/coreapi/private.h b/coreapi/private.h index 948bac604..4c3459ef8 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -91,7 +91,7 @@ struct _LinphoneCallParams{ int down_ptime; int up_ptime; char *record_file; - char *subject; + char *session_name; SalCustomHeader *custom_headers; bool_t has_video; bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/ From 3a405aab8b20b88e9b914dc39aaf4f13265f4ae3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 19 Feb 2014 12:07:19 +0100 Subject: [PATCH 259/439] fix unitialized expire in linphonec --- console/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/console/commands.c b/console/commands.c index 981c0ac60..ee876ebdb 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1516,7 +1516,7 @@ linphonec_proxy_add(LinphoneCore *lc) continue; } - cfg=linphone_proxy_config_new(); + cfg=linphone_core_create_proxy_config(lc); if (linphone_proxy_config_set_server_addr(cfg,clean)<0) { linphonec_out("Invalid sip address (sip:sip.domain.tld).\n"); From a777c5ac86598fd4bf99b19a200e725e7808bcac Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 19 Feb 2014 14:30:51 +0100 Subject: [PATCH 260/439] Add zrtpcppcore in linphone-deps --- linphone-deps.filelist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 53bab22af..fd8e6da17 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -17,5 +17,5 @@ ./bin/libgnutls-26.dll ./bin/libtasn1-3.dll ./bin/libsqlite3-0.dll -./bin/libzrtpcpp.dll +./bin/zrtpcppcore.dll ./bin/libopus-0.dll From 80165d909841e6115a14347b0e47c26254fcbe91 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 19 Feb 2014 16:33:47 +0100 Subject: [PATCH 261/439] Update README --- README.macos | 2 +- README.mingw | 19 +++++++++++-------- coreapi/callbacks.c | 2 +- coreapi/linphonecore.c | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/README.macos b/README.macos index 35e03044d..05a00e080 100644 --- a/README.macos +++ b/README.macos @@ -17,7 +17,7 @@ You need: $ sudo port install automake autoconf libtool intltool wget cunit - Install some linphone dependencies with macports - $ sudo port install antlr3 speex opus libvpx readline sqlite3 libsoup openldap + $ sudo port install antlr3 speex libvpx readline sqlite3 libsoup openldap $ sudo port install ffmpeg-devel -gpl2 - Install gtk. It is recommended to use the quartz backend for better integration. diff --git a/README.mingw b/README.mingw index 4ac4661a7..9e9e78075 100644 --- a/README.mingw +++ b/README.mingw @@ -1,13 +1,16 @@ Software to install ******************* -Download lastest mingw-get-inst.exe from http://www.mingw.org -Run mingw-get-inst.exe. Choose "download lastest catalogues". -In the feature list, select: -* C compiler -* C++ compiler -* Mingw developer toolkit -Let the installer fetch and install everything. +Download lastest mingw-get-setup.exe from http://www.mingw.org +Run mingw-get-setup.exe. +In the package list, select and install: +* mingw32-developer-tool +* mingw32-base +* mingw32-gcc-g++ +* msys-base + +For more information: +http://www.mingw.org/wiki/Getting_Started In mingw shell (also refered as msys), run @@ -37,7 +40,7 @@ unzip #Install GTK+ Outcrop theme, the one used by linphone for distribution. cd /share/themes -wget http://art.gnome.org/download/themes/gtk2/1122/GTK2-Outcrop.tar.gz +wget ftp://ftp.gnome.org/mirror/gnome.org/teams/art.gnome.org/themes/gtk2/GTK2-Outcrop.tar.gz tar -xvzf GTK2-Outcrop.tar.gz #To get the translations working, remove from C:/MinGW/lib : diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a31ac04d7..9c99e2722 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -764,7 +764,7 @@ static void register_success(SalOp *op, bool_t registered){ } linphone_proxy_config_set_error(cfg,LinphoneReasonNone); linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared , - registered ? "Registration sucessful" : "Unregistration done"); + registered ? "Registration successful" : "Unregistration done"); if (lc->vtable.display_status){ if (registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op)); else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op)); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 812565ac9..d5118a8a9 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3191,7 +3191,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) * @param lc the linphone core object. * @param call the LinphoneCall object * @param params a LinphoneCallParams object describing the call parameters to accept. - * @return 0 if sucessful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state). + * @return 0 if successful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state). **/ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ SalMediaDescription *remote_desc; From 9dc162783ec07085114e63e8b821ba8cc99873f1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 19 Feb 2014 16:46:09 +0100 Subject: [PATCH 262/439] Updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 1de47782b..60a3af972 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1de47782b0598594d8c6c55e9ff641da51326719 +Subproject commit 60a3af972a3e18b7616eaf6dd1f53acb2cb675a7 From 7ba75ee2ded9afcfca89a1b5a21601d7bbb66eae Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 19 Feb 2014 15:33:12 +0100 Subject: [PATCH 263/439] New 3.7.0 release --- NEWS | 10 +++++++++- README | 2 +- configure.ac | 21 +++++---------------- oRTP | 2 +- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/NEWS b/NEWS index 872a678fa..6fada612f 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -linphone-3.7...?? +linphone-3.7.0 -- February 20th, 2014 Application level improvements: * It is now possible to configure multiple proxy accounts with different transports (UDP, TCP, TLS) * can work with IPv6 and IPv4 simultaneously @@ -7,6 +7,9 @@ linphone-3.7...?? * Keyboard can be used for DTMF input * Faster and higly responsive UI thanks to fully asynchronous operation of the liblinphone. * Addon of opus codec + * Possibility to specify a remote provisionning http URI for configuration + * LDAP search integration for Linux and MacOSX + * is-composing notification in chat area Liblinphone level improvements thanks to new "belle-sip" SIP stack: * multiple SIP transports simultaneously now allowed @@ -20,7 +23,12 @@ linphone-3.7...?? * Privacy API (RFC3323, RFC3325) * Full support of rich presence in (RFC4480) * Better handling of sips scheme in URIs. + * Messaging: support of is-composing (RFC3994) + * Call transfer fixes in error cases + * Add API for managing SIP SUBSCRIBES/NOTIFY/PUBLISH (linphonecore/event.h) + * bugfixes + Requires: mediastreamer2 = 2.10.0, ortp = 0.23.0, belle-sip = 1.3.0 linphone-3.6.1 -- June 17, 2013 * fix memory leak with some video cameras on windows. diff --git a/README b/README index 0e913479e..a2fe5301e 100644 --- a/README +++ b/README @@ -8,7 +8,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. - intltool - you need at least: - - belle-sip>=1.0.0 + - belle-sip>=1.3.0 - speex>=1.2.0 (including libspeexdsp part) - libxml2 diff --git a/configure.ac b/configure.ac index c12172764..1f87cc62f 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.99],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.7.0],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) @@ -17,7 +17,7 @@ if test "$LINPHONE_EXTRA_VERSION" != "" ;then LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION} fi -LIBLINPHONE_SO_CURRENT=5 dnl increment this number when you add/change/remove an interface +LIBLINPHONE_SO_CURRENT=6 dnl increment this number when you add/change/remove an interface LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface @@ -584,17 +584,6 @@ AC_ARG_ENABLE(zrtp, [zrtp=false] ) - -AC_ARG_ENABLE(portaudio, - [AS_HELP_STRING([--enable-portaudio], [Turn on portaudio native support compiling])], - [case "${enableval}" in - yes) portaudio=true ;; - no) portaudio=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-portaudio) ;; - esac], - [portaudio=false] -) - dnl build console if required AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue) @@ -696,7 +685,7 @@ AC_ARG_ENABLE([external-mediastreamer], AS_CASE($enable_external_mediastreamer, [yes], - [PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer]) + [PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer>=2.10.0]) MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer`], [no], [AC_CONFIG_SUBDIRS( mediastreamer2 ) @@ -761,7 +750,7 @@ if test x$enable_msg_storage != xfalse; then fi -PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.2.0]) +PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.3.0]) SIPSTACK_CFLAGS="$BELLESIP_CFLAGS" SIPSTACK_LIBS="$BELLESIP_LIBS" @@ -798,7 +787,7 @@ AC_ARG_ENABLE(external-ortp, ) if test "$external_ortp" = 'true'; then - PKG_CHECK_MODULES([ORTP], [ortp]) + PKG_CHECK_MODULES([ORTP], [ortp>=0.23.0]) ORTP_VERSION=`$PKG_CONFIG --modversion ortp` else AC_CONFIG_SUBDIRS( oRTP ) diff --git a/oRTP b/oRTP index 747129fc3..7bac4a3ec 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 747129fc30c79d0eb416217782da531ccf3cc71f +Subproject commit 7bac4a3ecaa2e74e9e4fd3de2c2ddb57fe7945d6 From 60f6726c61d463c43e6038b629628f509add2e3c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 19 Feb 2014 18:07:04 +0100 Subject: [PATCH 264/439] Fix bug from code deactivated when video was not enabled. --- coreapi/linphonecore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d5118a8a9..c2ff6a028 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3077,10 +3077,12 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho } #endif //BUILD_UPNP } - +#endif /* VIDEO_ENABLED */ + _linphone_call_params_copy(&call->params,params); linphone_call_make_local_media_description(lc, call); +#ifdef VIDEO_ENABLED // Video adding if (!has_video && call->params.has_video) { if (call->ice_session != NULL) { From 519430c42e5e617f9e132dcc99237dd0f9167bcf Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 19 Feb 2014 22:35:48 +0100 Subject: [PATCH 265/439] simplify creation of custom headers --- coreapi/bellesip_sal/sal_impl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index eacc38686..62610f406 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -800,16 +800,14 @@ int sal_auth_compute_ha1(const char* userid,const char* realm,const char* passwo SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){ belle_sip_message_t *msg=(belle_sip_message_t*)ch; belle_sip_header_t *h; - char *tmp=ms_strdup_printf("%s: %s\r\n",name,value); if (msg==NULL){ msg=(belle_sip_message_t*)belle_sip_request_new(); belle_sip_object_ref(msg); } - h=belle_sip_header_parse(tmp); - ms_free(tmp); + h=belle_sip_header_create(name,value); if (h==NULL){ - belle_sip_error("Fail to parse extension header."); + belle_sip_error("Fail to parse custom header."); return (SalCustomHeader*)msg; } belle_sip_message_add_header(msg,h); From 3d28615ffd45a8157ad7b9e1b7ce888b1534d0ec Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 20 Feb 2014 09:49:18 +0100 Subject: [PATCH 266/439] Fix PKG_CHECK_MODULES with versions. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 1f87cc62f..a8114f18b 100644 --- a/configure.ac +++ b/configure.ac @@ -685,7 +685,7 @@ AC_ARG_ENABLE([external-mediastreamer], AS_CASE($enable_external_mediastreamer, [yes], - [PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer>=2.10.0]) + [PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer >= 2.10.0]) MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer`], [no], [AC_CONFIG_SUBDIRS( mediastreamer2 ) @@ -787,7 +787,7 @@ AC_ARG_ENABLE(external-ortp, ) if test "$external_ortp" = 'true'; then - PKG_CHECK_MODULES([ORTP], [ortp>=0.23.0]) + PKG_CHECK_MODULES([ORTP], [ortp >= 0.23.0]) ORTP_VERSION=`$PKG_CONFIG --modversion ortp` else AC_CONFIG_SUBDIRS( oRTP ) From e31a4256ac52904d036d231e84e5e1dcea0f1c68 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 20 Feb 2014 09:50:20 +0100 Subject: [PATCH 267/439] Increase version in CMake. --- coreapi/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index b608e4bfb..85a03061e 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -118,7 +118,7 @@ endif(WIN32) set(LIBS ${LIBS} ${LIBORTP} ${LIBMEDIASTREAMER_BASE} ${LIBMEDIASTREAMER_VOIP} ${LIBBELLESIP} ${LIBXML2}) add_library(linphone SHARED ${SOURCE_FILES}) -set_target_properties(linphone PROPERTIES VERSION 3.6.99 SOVERSION 5) +set_target_properties(linphone PROPERTIES VERSION 3.7.0 SOVERSION 5) target_link_libraries(linphone ${LIBS}) From 1372da9628fd6a04a7ff1b74fca4db12d4bc5268 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 20 Feb 2014 11:38:55 +0100 Subject: [PATCH 268/439] Move rcfiles of tester in a subdirectory. --- tester/Makefile.am | 4 +--- tester/liblinphone_tester.c | 5 ++++- tester/{ => rcfiles}/empty_rc | 0 tester/{ => rcfiles}/laure_rc | 0 tester/{ => rcfiles}/marie_early_rc | 0 tester/{ => rcfiles}/marie_no_sdp_rc | 0 tester/{ => rcfiles}/marie_rc | 0 tester/{ => rcfiles}/marie_remote_404_rc | 0 tester/{ => rcfiles}/marie_remote_https_rc | 0 tester/{ => rcfiles}/marie_remote_invalid_rc | 0 tester/{ => rcfiles}/marie_remote_rc | 0 tester/{multi_account_lrc => rcfiles/multi_account_rc} | 0 tester/{ => rcfiles}/pauline_alt_rc | 0 tester/{ => rcfiles}/pauline_rc | 0 tester/{ => rcfiles}/pauline_tcp_rc | 0 tester/{ => rcfiles}/pauline_wild_rc | 0 tester/{ => rcfiles}/stun_rc | 0 tester/{ => rcfiles}/upnp_rc | 0 tester/register_tester.c | 4 ++-- 19 files changed, 7 insertions(+), 6 deletions(-) rename tester/{ => rcfiles}/empty_rc (100%) rename tester/{ => rcfiles}/laure_rc (100%) rename tester/{ => rcfiles}/marie_early_rc (100%) rename tester/{ => rcfiles}/marie_no_sdp_rc (100%) rename tester/{ => rcfiles}/marie_rc (100%) rename tester/{ => rcfiles}/marie_remote_404_rc (100%) rename tester/{ => rcfiles}/marie_remote_https_rc (100%) rename tester/{ => rcfiles}/marie_remote_invalid_rc (100%) rename tester/{ => rcfiles}/marie_remote_rc (100%) rename tester/{multi_account_lrc => rcfiles/multi_account_rc} (100%) rename tester/{ => rcfiles}/pauline_alt_rc (100%) rename tester/{ => rcfiles}/pauline_rc (100%) rename tester/{ => rcfiles}/pauline_tcp_rc (100%) rename tester/{ => rcfiles}/pauline_wild_rc (100%) rename tester/{ => rcfiles}/stun_rc (100%) rename tester/{ => rcfiles}/upnp_rc (100%) diff --git a/tester/Makefile.am b/tester/Makefile.am index f5344b13f..5c1f72239 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -1,6 +1,4 @@ -EXTRA_DIST= empty_rc laure_rc marie_early_rc marie_no_sdp_rc marie_rc multi_account_lrc pauline_alt_rc \ - marie_remote_rc marie_remote_https_rc marie_remote_404_rc marie_remote_invalid_rc \ - pauline_rc pauline_wild_rc pauline_tcp_rc tester_hosts sounds images certificates +EXTRA_DIST= tester_hosts sounds images certificates rcfiles if BUILD_CUNIT_TESTS diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 7a7346f51..6854b086d 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -184,6 +184,7 @@ LinphoneCoreManager *get_manager(LinphoneCore *lc){ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies) { LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); LinphoneProxyConfig* proxy; + char *rc_path = NULL; int proxy_count; int retry=0; @@ -203,7 +204,8 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->v_table.configuring_status=linphone_configuration_status; reset_counters(&mgr->stat); - mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_file, mgr); + if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file); + mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_path, mgr); /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ if (check_for_proxies && rc_file) /**/ proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)); @@ -222,6 +224,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); linphone_address_clean(mgr->identity); } + if (rc_path) ms_free(rc_path); return mgr; } diff --git a/tester/empty_rc b/tester/rcfiles/empty_rc similarity index 100% rename from tester/empty_rc rename to tester/rcfiles/empty_rc diff --git a/tester/laure_rc b/tester/rcfiles/laure_rc similarity index 100% rename from tester/laure_rc rename to tester/rcfiles/laure_rc diff --git a/tester/marie_early_rc b/tester/rcfiles/marie_early_rc similarity index 100% rename from tester/marie_early_rc rename to tester/rcfiles/marie_early_rc diff --git a/tester/marie_no_sdp_rc b/tester/rcfiles/marie_no_sdp_rc similarity index 100% rename from tester/marie_no_sdp_rc rename to tester/rcfiles/marie_no_sdp_rc diff --git a/tester/marie_rc b/tester/rcfiles/marie_rc similarity index 100% rename from tester/marie_rc rename to tester/rcfiles/marie_rc diff --git a/tester/marie_remote_404_rc b/tester/rcfiles/marie_remote_404_rc similarity index 100% rename from tester/marie_remote_404_rc rename to tester/rcfiles/marie_remote_404_rc diff --git a/tester/marie_remote_https_rc b/tester/rcfiles/marie_remote_https_rc similarity index 100% rename from tester/marie_remote_https_rc rename to tester/rcfiles/marie_remote_https_rc diff --git a/tester/marie_remote_invalid_rc b/tester/rcfiles/marie_remote_invalid_rc similarity index 100% rename from tester/marie_remote_invalid_rc rename to tester/rcfiles/marie_remote_invalid_rc diff --git a/tester/marie_remote_rc b/tester/rcfiles/marie_remote_rc similarity index 100% rename from tester/marie_remote_rc rename to tester/rcfiles/marie_remote_rc diff --git a/tester/multi_account_lrc b/tester/rcfiles/multi_account_rc similarity index 100% rename from tester/multi_account_lrc rename to tester/rcfiles/multi_account_rc diff --git a/tester/pauline_alt_rc b/tester/rcfiles/pauline_alt_rc similarity index 100% rename from tester/pauline_alt_rc rename to tester/rcfiles/pauline_alt_rc diff --git a/tester/pauline_rc b/tester/rcfiles/pauline_rc similarity index 100% rename from tester/pauline_rc rename to tester/rcfiles/pauline_rc diff --git a/tester/pauline_tcp_rc b/tester/rcfiles/pauline_tcp_rc similarity index 100% rename from tester/pauline_tcp_rc rename to tester/rcfiles/pauline_tcp_rc diff --git a/tester/pauline_wild_rc b/tester/rcfiles/pauline_wild_rc similarity index 100% rename from tester/pauline_wild_rc rename to tester/rcfiles/pauline_wild_rc diff --git a/tester/stun_rc b/tester/rcfiles/stun_rc similarity index 100% rename from tester/stun_rc rename to tester/rcfiles/stun_rc diff --git a/tester/upnp_rc b/tester/rcfiles/upnp_rc similarity index 100% rename from tester/upnp_rc rename to tester/rcfiles/upnp_rc diff --git a/tester/register_tester.c b/tester/register_tester.c index 4705ba13f..547c2cec4 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -365,7 +365,7 @@ static void authenticated_register_with_wrong_credentials_without_403() { authenticated_register_with_wrong_credentials_with_params("tester-no-403"); } static LinphoneCoreManager* configure_lcm(void) { - LinphoneCoreManager *mgr=linphone_core_manager_new( "multi_account_lrc"); + LinphoneCoreManager *mgr=linphone_core_manager_new( "multi_account_rc"); 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; @@ -487,7 +487,7 @@ static void io_recv_error_late_recovery(){ 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*/ + mgr=linphone_core_manager_new2( "multi_account_rc",FALSE); /*to make sure iterates are not call yet*/ lc=mgr->lc; sal_set_refresher_retry_after(lc->sal,1000); counters=&mgr->stat; From 493a1fec08d36c0868c963f34151fd08576b824f Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 20 Feb 2014 15:37:39 +0100 Subject: [PATCH 269/439] Fix failing custom header tests failing --- coreapi/callbacks.c | 2 +- coreapi/linphonecall.c | 18 ++++++------------ tester/call_tester.c | 27 ++++++++++++++++++--------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9c99e2722..033b1660b 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -627,7 +627,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de || call->state==LinphoneCallOutgoingProgress || call->state==LinphoneCallOutgoingRinging /*push case*/ || call->state==LinphoneCallOutgoingEarlyMedia){ - LinphoneAddress* redirection_to = linphone_call_get_remote_contact_address(call); + LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op); if( redirection_to ){ char* url = linphone_address_as_string(redirection_to); ms_error("Redirecting call [%p] to %s",call, url); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 901fcf5be..820ee3427 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1058,18 +1058,12 @@ const char *linphone_call_get_remote_user_agent(LinphoneCall *call){ * Returns the far end's sip contact as a string, if available. **/ const char *linphone_call_get_remote_contact(LinphoneCall *call){ - if (call->op){ - return sal_op_get_remote_contact(call->op); - } - return NULL; -} - -/** - * Returns the far end's sip contact as a string, if available. -**/ -LinphoneAddress *linphone_call_get_remote_contact_address(LinphoneCall *call){ - if (call->op){ - return (LinphoneAddress*)sal_op_get_remote_contact_address(call->op); + const LinphoneCallParams* lcp = linphone_call_get_remote_params(call); + if( lcp ){ + // we're not using sal_op_get_remote_contact() here because the returned value is stripped from + // params that we need, like the instanceid. Getting it from the headers will make sure we + // get everything + return linphone_call_params_get_custom_header(lcp, "Contact"); } return NULL; } diff --git a/tester/call_tester.c b/tester/call_tester.c index 2b40e6bf0..6c8710dba 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -550,9 +550,9 @@ static void call_with_custom_headers(void) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall *call_marie,*call_pauline; LinphoneCallParams *params; - const LinphoneCallParams *remote_params; + const LinphoneCallParams *marie_remote_params; const char *hvalue; - const char *pauline_remote_contact_header, + char *pauline_remote_contact_header, *pauline_remote_contact, *marie_remote_contact, *marie_remote_contact_header; @@ -578,19 +578,22 @@ static void call_with_custom_headers(void) { CU_ASSERT_PTR_NOT_NULL(call_marie); CU_ASSERT_PTR_NOT_NULL(call_pauline); - remote_params=linphone_call_get_remote_params(call_marie); - hvalue=linphone_call_params_get_custom_header(remote_params,"Weather"); + marie_remote_params=linphone_call_get_remote_params(call_marie); + hvalue=linphone_call_params_get_custom_header(marie_remote_params,"Weather"); CU_ASSERT_PTR_NOT_NULL(hvalue); CU_ASSERT_STRING_EQUAL(hvalue,"bad"); - hvalue=linphone_call_params_get_custom_header(remote_params,"uriHeader"); + hvalue=linphone_call_params_get_custom_header(marie_remote_params,"uriHeader"); CU_ASSERT_PTR_NOT_NULL(hvalue); CU_ASSERT_STRING_EQUAL(hvalue,"myUriHeader"); - pauline_remote_contact_header = linphone_call_params_get_custom_header(linphone_call_get_remote_params(call_pauline), "Contact"); - pauline_remote_contact = linphone_call_get_remote_contact(call_pauline); - marie_remote_contact = linphone_call_get_remote_contact(call_marie); - marie_remote_contact_header = linphone_call_params_get_custom_header(remote_params, "Contact"); + // FIXME: we have to strdup because successive calls to get_remote_params erase the returned const char*!! + pauline_remote_contact = ms_strdup(linphone_call_get_remote_contact(call_pauline)); + pauline_remote_contact_header = ms_strdup(linphone_call_params_get_custom_header(linphone_call_get_remote_params(call_pauline), "Contact")); + + marie_remote_contact = ms_strdup(linphone_call_get_remote_contact(call_marie)); + marie_remote_contact_header = ms_strdup(linphone_call_params_get_custom_header(marie_remote_params, "Contact")); + CU_ASSERT_PTR_NOT_NULL(pauline_remote_contact); CU_ASSERT_PTR_NOT_NULL(pauline_remote_contact_header); CU_ASSERT_PTR_NOT_NULL(marie_remote_contact); @@ -598,6 +601,12 @@ static void call_with_custom_headers(void) { CU_ASSERT_STRING_EQUAL(pauline_remote_contact,pauline_remote_contact_header); CU_ASSERT_STRING_EQUAL(marie_remote_contact,marie_remote_contact_header); + ms_free(pauline_remote_contact); + ms_free(pauline_remote_contact_header); + ms_free(marie_remote_contact); + ms_free(marie_remote_contact_header); + + /*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 161540a1cf701ba93fb9bf78285c65cd436089d5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 20 Feb 2014 15:41:10 +0100 Subject: [PATCH 270/439] cosmetic changes --- coreapi/bellesip_sal/sal_address_impl.c | 2 ++ coreapi/bellesip_sal/sal_op_impl.c | 6 ++++-- mediastreamer2 | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index f73a06240..024b83264 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -31,9 +31,11 @@ SalAddress * sal_address_new(const char *uri){ if (result) belle_sip_object_ref(result); return (SalAddress *)result; } + SalAddress * sal_address_clone(const SalAddress *addr){ return (SalAddress *) belle_sip_object_ref(belle_sip_object_clone(BELLE_SIP_OBJECT(addr))); } + const char *sal_address_get_scheme(const SalAddress *addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index e1b5d7a0b..d7b6c0c1d 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -564,8 +564,10 @@ void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){ } const char *sal_op_get_remote_contact(const SalOp *op){ - // remote contact is filled in process_response -// return sal_custom_header_find(op->base.recv_custom_headers,"Contact"); + /* + * remote contact is filled in process_response + * return sal_custom_header_find(op->base.recv_custom_headers,"Contact"); + */ return op->base.remote_contact; } diff --git a/mediastreamer2 b/mediastreamer2 index 60a3af972..77b6e16c9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 60a3af972a3e18b7616eaf6dd1f53acb2cb675a7 +Subproject commit 77b6e16c9ef07fdbb741d220c89e749ff746d654 From 11812765e4df17dbc816a5c596b64dfce25acb61 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 20 Feb 2014 15:57:40 +0100 Subject: [PATCH 271/439] relax a bit tests --- tester/flexisip_tester.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index b2bae56df..08466d709 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -108,14 +108,14 @@ static void message_forking_with_unreachable_recipients(void) { CU_ASSERT_TRUE( marie3->stat.number_of_LinphoneMessageReceived==0); /*marie 2 goes online */ linphone_core_set_network_reachable(marie2->lc,TRUE); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,3000)); /*wait a long time so that all transactions are expired*/ wait_for_list(lcs,NULL,0,32000); /*marie 3 goes online now*/ linphone_core_set_network_reachable(marie3->lc,TRUE); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneMessageReceived,1,3000)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(marie2); @@ -154,18 +154,18 @@ static void message_forking_with_all_recipients_unreachable(void) { /*marie 1 goes online */ linphone_core_set_network_reachable(marie->lc,TRUE); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,3000)); /*marie 2 goes online */ linphone_core_set_network_reachable(marie2->lc,TRUE); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,3000)); /*wait a long time so that all transactions are expired*/ wait_for_list(lcs,NULL,0,32000); /*marie 3 goes online now*/ linphone_core_set_network_reachable(marie3->lc,TRUE); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneMessageReceived,1,3000)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(marie2); From 779e104f4f912963069b1a5137518c1cb1334671 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 20 Feb 2014 16:54:04 +0100 Subject: [PATCH 272/439] Use ortp_qnx_log_handler for liblinphone_tester on BlackBerry 10. --- tester/liblinphone_tester.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 6854b086d..2cb84fca0 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -424,6 +424,12 @@ static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, } #endif +#ifdef __QNX__ +static void liblinphone_tester_qnx_log_handler(OrtpLogLevel lev, const char *fmt, va_list args) { + ortp_qnx_log_handler("liblinphone_tester", lev, fmt, args); +} +#endif /* __QNX__ */ + void helper(const char *name) { fprintf(stderr,"%s \t--help\n" "\t\t\t--verbose\n" @@ -455,6 +461,14 @@ int main (int argc, char *argv[]) { const char *suite_name=NULL; const char *test_name=NULL; +#if defined(ANDROID) + linphone_core_set_log_handler(linphone_android_ortp_log_handler); +#elif defined(__QNX__) + linphone_core_set_log_handler(liblinphone_tester_qnx_log_handler); +#else + linphone_core_set_log_file(NULL); +#endif + liblinphone_tester_init(); for(i=1;i Date: Fri, 21 Feb 2014 09:37:59 +0100 Subject: [PATCH 273/439] relax again wait times in tests --- tester/flexisip_tester.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 08466d709..4218c1009 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -243,7 +243,7 @@ static void call_forking_with_urgent_reply(void){ linphone_core_invite_address(pauline->lc,marie->identity); /*pauline should hear ringback, after 5 seconds, when it will retry without SRTP*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,6000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,9000)); /*Marie should be ringing*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); From ce6f19d7ac2946f55bbca40daa3ad7bf8e6b0ebd Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 21 Feb 2014 14:13:51 +0100 Subject: [PATCH 274/439] Implement linphone_core_accept_early_media --- coreapi/linphonecore.c | 41 +++++++++++++++++++++++++++++++++++ coreapi/linphonecore.h | 4 ++++ tester/call_tester.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c2ff6a028..fa290f411 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3012,6 +3012,47 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ ms_free(tmp); } +int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, bool_t early_media, LinphoneCallParams* params) { + if (call->state==LinphoneCallIncomingReceived){ + SalMediaDescription* md; + + /*try to be best-effort in giving real local or routable contact address for 100Rel case*/ + linphone_call_set_contact_op(call); + + // if parameters are passed, update the media description + if ( params ) { + md = sal_call_get_remote_media_description ( call->op ); + _linphone_call_params_copy ( &call->params,params ); + + // There might not be a md if the INVITE was lacking an SDP + // In this case we use the parameters as is. + if ( md ) call->params.has_video &= linphone_core_media_description_contains_video_stream ( md ); + + linphone_call_make_local_media_description ( lc,call ); + sal_call_set_local_media_description ( call->op,call->localdesc ); + sal_op_set_sent_custom_header ( call->op,params->custom_headers ); + } + + sal_call_notify_ringing(call->op,early_media); + + if (early_media){ + linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); + md=sal_call_get_final_media_description(call->op); + if (md) linphone_core_update_streams(lc,call,md); + } + if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ + linphone_core_accept_call(lc,call); + } + return 0; + } + + return -1; +} + +int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call, bool_t early_media){ + return linphone_core_accept_early_media_with_params(lc, call, early_media, NULL); +} + int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ const char *subject; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 291748312..a98e29be0 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1404,6 +1404,10 @@ LINPHONE_PUBLIC int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *ca LINPHONE_PUBLIC int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); +LINPHONE_PUBLIC int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, bool_t early_media, LinphoneCallParams* params); + +LINPHONE_PUBLIC int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call, bool_t early_media); + LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); /** diff --git a/tester/call_tester.c b/tester/call_tester.c index 6c8710dba..8e4f80771 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1080,6 +1080,54 @@ static void early_media_call(void) { linphone_core_manager_destroy(pauline); } +static void early_media_call_with_ringing(void){ + + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc"); + MSList* lcs = NULL; + LinphoneCall* marie_call; + + lcs = ms_list_append(lcs,marie->lc); + lcs = ms_list_append(lcs,pauline->lc); + /* + Marie calls Pauline, and after the call has rung, transitions to an early_media session + */ + + marie_call = linphone_core_invite_address(marie->lc, pauline->identity); + + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + + + /* send a 183 to initiate the early media */ + + linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc), TRUE); + + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) ); + + liblinphone_tester_check_rtcp(marie, pauline); + + linphone_core_accept_call(pauline->lc, linphone_core_get_current_call(pauline->lc)); + + CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1,1000)); + + CU_ASSERT_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); + + liblinphone_tester_check_rtcp(marie, pauline); + + 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,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + + + ms_list_free(lcs); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void simple_call_transfer(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -1548,6 +1596,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 with ringing", early_media_call_with_ringing }, { "Call terminated by caller", call_terminated_by_caller }, { "Call without SDP", call_with_no_sdp}, { "Call paused resumed", call_paused_resumed }, From 665e627c10da148397ebc49fb2517be0a5639a2d Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 21 Feb 2014 14:13:59 +0100 Subject: [PATCH 275/439] Fix memory leak --- tester/call_tester.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tester/call_tester.c b/tester/call_tester.c index 8e4f80771..5f6540ad9 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1493,6 +1493,8 @@ static void call_redirect(void){ CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); + ms_list_free(lcs); + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(laure); From 3b3271dbb0895081789c23f471c231d3cc50199b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 21 Feb 2014 15:42:40 +0100 Subject: [PATCH 276/439] fix early media API and implementation --- coreapi/linphonecore.c | 57 +++++++++++++++++++++++++----------------- coreapi/linphonecore.h | 4 +-- tester/call_tester.c | 2 +- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index fa290f411..70caaa6c6 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2995,13 +2995,11 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *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){ - linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); - md=sal_call_get_final_media_description(call->op); - if (md) linphone_core_update_streams(lc,call,md); - } + linphone_core_accept_early_media(lc,call); + }else sal_call_notify_ringing(call->op,FALSE); + if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ linphone_core_accept_call(lc,call); } @@ -3012,7 +3010,19 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ ms_free(tmp); } -int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, bool_t early_media, LinphoneCallParams* params) { + +/** + * When receiving an incoming, accept to start a media session as early-media. + * This means the call is not accepted but audio & video streams can be established if the remote party supports early media. + * However, unlike after call acceptance, mic and camera input are not sent during early-media, though received audio & video are played normally. + * The call can then later be fully accepted using linphone_core_accept_call() or linphone_core_accept_call_with_params(). + * @param lc the linphonecore + * @param call the call + * @param params the call params, can be NULL. + * @return 0 if successful, -1 otherwise. + * @ingroup call_control +**/ +int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params) { if (call->state==LinphoneCallIncomingReceived){ SalMediaDescription* md; @@ -3023,34 +3033,35 @@ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* if ( params ) { md = sal_call_get_remote_media_description ( call->op ); _linphone_call_params_copy ( &call->params,params ); - - // There might not be a md if the INVITE was lacking an SDP - // In this case we use the parameters as is. - if ( md ) call->params.has_video &= linphone_core_media_description_contains_video_stream ( md ); - linphone_call_make_local_media_description ( lc,call ); sal_call_set_local_media_description ( call->op,call->localdesc ); sal_op_set_sent_custom_header ( call->op,params->custom_headers ); } - sal_call_notify_ringing(call->op,early_media); + sal_call_notify_ringing(call->op,TRUE); - if (early_media){ - linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); - md=sal_call_get_final_media_description(call->op); - if (md) linphone_core_update_streams(lc,call,md); - } - if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ - linphone_core_accept_call(lc,call); - } + linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); + md=sal_call_get_final_media_description(call->op); + if (md) linphone_core_update_streams(lc,call,md); return 0; + }else{ + ms_error("Bad state %s for linphone_core_accept_early_media_with_params()", linphone_call_state_to_string(call->state)); } return -1; } -int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call, bool_t early_media){ - return linphone_core_accept_early_media_with_params(lc, call, early_media, NULL); +/** + * Accept an early media session for an incoming call. + * This is identical as calling linphone_core_accept_early_media_with_params() with NULL call parameters. + * @see linphone_core_accept_early_media_with_params() + * @param lc the core + * @param call the incoming call + * @return 0 if successful, -1 otherwise. + * @ingroup call_control +**/ +int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call){ + return linphone_core_accept_early_media_with_params(lc, call, NULL); } int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index a98e29be0..f230e6657 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1404,9 +1404,9 @@ LINPHONE_PUBLIC int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *ca LINPHONE_PUBLIC int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); -LINPHONE_PUBLIC int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, bool_t early_media, LinphoneCallParams* params); +LINPHONE_PUBLIC int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params); -LINPHONE_PUBLIC int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call, bool_t early_media); +LINPHONE_PUBLIC int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call); LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); diff --git a/tester/call_tester.c b/tester/call_tester.c index 5f6540ad9..3f84eaf27 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1101,7 +1101,7 @@ static void early_media_call_with_ringing(void){ /* send a 183 to initiate the early media */ - linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc), TRUE); + linphone_core_accept_early_media(pauline->lc, linphone_core_get_current_call(pauline->lc)); CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia,1,2000) ); CU_ASSERT_TRUE( wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,2000) ); From 15c8ed30f58320317b3cc4f132281cca55710a85 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 21 Feb 2014 18:34:52 +0100 Subject: [PATCH 277/439] modify event API to allow adding custom headers. It is now possible to first create the LinphoneEvent, configure it with custom headers, then send it. --- coreapi/event.c | 121 ++++++++++++++++++++++++++------------- coreapi/event.h | 65 ++++++++++++++++++++- coreapi/private.h | 4 +- tester/eventapi_tester.c | 68 +++++++++++++++++++++- 4 files changed, 212 insertions(+), 46 deletions(-) diff --git a/coreapi/event.c b/coreapi/event.c index 37bbbb076..6a7930943 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -35,7 +35,7 @@ const char *linphone_subscription_state_to_string(LinphoneSubscriptionState stat switch(state){ case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone"; case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived"; - case LinphoneSubscriptionOutoingInit: return "LinphoneSubscriptionOutoingInit"; + case LinphoneSubscriptionOutgoingInit: return "LinphoneSubscriptionOutoingInit"; case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending"; case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive"; case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated"; @@ -68,8 +68,9 @@ static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscri return lev; } -LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name){ +LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires){ LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, sal_op_new(lc->sal)); + lev->expires=expires; return lev; } @@ -121,32 +122,38 @@ LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ return lev->reason; } -LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ - LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event); - SalBody salbody; +LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){ + LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event, expires); linphone_configure_op(lc,lev->op,resource,NULL,TRUE); sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1)); lev->resource_addr=linphone_address_clone(resource); lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op)); - sal_subscribe(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); - linphone_event_set_state(lev,LinphoneSubscriptionOutoingInit); + return lev; +} + +LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ + LinphoneEvent *lev=linphone_core_create_subscribe(lc,resource,event,expires); + linphone_event_send_subscribe(lev,body); return lev; } -int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){ +int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *body){ SalBody salbody; + int err; + + if (lev->dir!=LinphoneSubscriptionOutgoing){ + ms_error("linphone_event_send_subscribe(): cannot send or update something that is not an outgoing subscription."); + return -1; + } switch (lev->subscription_state){ - case LinphoneSubscriptionNone: - ms_error("linphone_event_update_subscribe(): this is not a subscribed event."); - return -1; - break; case LinphoneSubscriptionIncomingReceived: - case LinphoneSubscriptionOutoingInit: case LinphoneSubscriptionTerminated: - ms_error("linphone_event_update_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state)); + case LinphoneSubscriptionOutgoingInit: + ms_error("linphone_event_send_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state)); return -1; break; + case LinphoneSubscriptionNone: case LinphoneSubscriptionActive: case LinphoneSubscriptionExpiring: case LinphoneSubscriptionError: @@ -154,11 +161,22 @@ int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *b /*those states are ok*/ break; } - if (lev->dir!=LinphoneSubscriptionOutgoing){ - ms_error("linphone_event_deny_subscription(): cannot update an incoming subscription."); - return -1; + + if (lev->send_custom_headers){ + sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers); + lev->send_custom_headers=NULL; + }else sal_op_set_sent_custom_header(lev->op,NULL); + + err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body)); + if (err==0){ + if (lev->subscription_state==LinphoneSubscriptionNone) + linphone_event_set_state(lev,LinphoneSubscriptionOutgoingInit); } - return sal_subscribe(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body)); + return err; +} + +int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){ + return linphone_event_send_subscribe(lev,body); } int linphone_event_accept_subscription(LinphoneEvent *lev){ @@ -198,40 +216,52 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){ return sal_notify(lev->op,sal_body_from_content(&salbody,body)); } -LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ - SalBody salbody; - int err; - LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event); +LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){ + LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires); linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0)); sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1)); - err=sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body)); + return lev; +} + +static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body, bool_t notify_err){ + SalBody salbody; + int err; + + if (lev->dir!=LinphoneSubscriptionInvalidDir){ + ms_error("linphone_event_update_publish(): this is not a PUBLISH event."); + return -1; + } + + err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body)); if (err==0){ linphone_event_set_publish_state(lev,LinphonePublishProgress); - }else{ + }else if (notify_err){ + linphone_event_set_publish_state(lev,LinphonePublishError); + } + return err; +} + +LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){ + int err; + LinphoneEvent *lev=linphone_core_create_publish(lc,resource,event,expires); + err=_linphone_event_send_publish(lev,body,FALSE); + if (err==-1){ linphone_event_unref(lev); lev=NULL; } return lev; } -int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body){ - SalBody salbody; - int err; - - if (lev->publish_state==LinphonePublishNone){ - ms_error("linphone_event_update_publish(): this is not a PUBLISH event."); - return -1; - } - - err=sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body)); - if (err==0){ - linphone_event_set_publish_state(lev,LinphonePublishProgress); - }else{ - linphone_event_set_publish_state(lev,LinphonePublishError); - } - return err; + +int linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body){ + return _linphone_event_send_publish(lev,body,TRUE); } +int linphone_event_update_publish(LinphoneEvent* lev, const LinphoneContent* body ) { + return linphone_event_send_publish(lev,body); +} + + void linphone_event_set_user_data(LinphoneEvent *ev, void *up){ ev->userdata=up; } @@ -240,6 +270,16 @@ void *linphone_event_get_user_data(const LinphoneEvent *ev){ return ev->userdata; } +void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value){ + ev->send_custom_headers=sal_custom_header_append(ev->send_custom_headers, name, value); +} + +const char* linphone_event_get_custom_header(LinphoneEvent* ev, const char* name){ + const SalCustomHeader *ch=sal_op_get_recv_custom_header(ev->op); + return sal_custom_header_find(ch,name); +} + + void linphone_event_terminate(LinphoneEvent *lev){ lev->terminating=TRUE; if (lev->dir==LinphoneSubscriptionIncoming){ @@ -259,7 +299,6 @@ void linphone_event_terminate(LinphoneEvent *lev){ linphone_event_set_state(lev,LinphoneSubscriptionTerminated); return; } - } diff --git a/coreapi/event.h b/coreapi/event.h index 9c7bccf35..e01ab9414 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -52,7 +52,7 @@ typedef enum _LinphoneSubscriptionDir LinphoneSubscriptionDir; **/ enum _LinphoneSubscriptionState{ LinphoneSubscriptionNone, /**< Initial state, should not be used.**/ - LinphoneSubscriptionOutoingInit, /**refresh_generic_subscribe property is set to 0.*/ }; +/*typo compatibility*/ +#define LinphoneSubscriptionOutoingInit LinphoneSubscriptionOutgoingInit /** * Typedef for subscription state enum. @@ -115,7 +117,28 @@ typedef void (*LinphoneCorePublishStateChangedCb)(LinphoneCore *lc, LinphoneEven LINPHONE_PUBLIC LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body); /** - * Update an outgoing subscription. + * Create an outgoing subscription, specifying the destination resource, the event name, and an optional content body. + * If accepted, the subscription runs for a finite period, but is automatically renewed if not terminated before. + * Unlike linphone_core_subscribe() the subscription isn't sent immediately. It will be send when calling linphone_event_send_subscribe(). + * @param lc the #LinphoneCore + * @param resource the destination resource + * @param event the event name + * @param expires the whished duration of the subscription + * @param body an optional body, may be NULL. + * @return a LinphoneEvent holding the context of the created subcription. +**/ +LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires); + +/** + * Send a subscription previously created by linphone_core_create_subscribe(). + * @param ev the LinphoneEvent + * @param body optional content to attach with the subscription. + * @return 0 if successful, -1 otherwise. +**/ +LINPHONE_PUBLIC int linphone_event_send_subscribe(LinphoneEvent *ev, const LinphoneContent *body); + +/** + * Update (refresh) an outgoing subscription. * @param lev a LinphoneEvent * @param body an optional body to include in the subscription update, may be NULL. **/ @@ -141,6 +164,7 @@ LINPHONE_PUBLIC int linphone_event_notify(LinphoneEvent *lev, const LinphoneCont /** * Publish an event state. + * This first create a LinphoneEvent with linphone_core_create_publish() and calls linphone_event_send_publish() to actually send it. * After expiry, the publication is refreshed unless it is terminated before. * @param lc the #LinphoneCore * @param resource the resource uri for the event @@ -152,7 +176,26 @@ LINPHONE_PUBLIC int linphone_event_notify(LinphoneEvent *lev, const LinphoneCont LINPHONE_PUBLIC LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body); /** - * Update a publication. + * Create a publish context for an event state. + * After being created, the publish must be sent using linphone_event_send_publish(). + * After expiry, the publication is refreshed unless it is terminated before. + * @param lc the #LinphoneCore + * @param resource the resource uri for the event + * @param event the event name + * @param expires the lifetime of the publication + * @return the LinphoneEvent holding the context of the publish. +**/ +LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires); + +/** + * Send a publish created by linphone_core_create_publish(). + * @param lev the #LinphoneEvent + * @param body the new data to be published +**/ +LINPHONE_PUBLIC int linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body); + +/** + * Update (refresh) a publish. * @param lev the #LinphoneEvent * @param body the new data to be published **/ @@ -190,6 +233,22 @@ LINPHONE_PUBLIC void linphone_event_set_user_data(LinphoneEvent *ev, void *up); **/ LINPHONE_PUBLIC void *linphone_event_get_user_data(const LinphoneEvent *ev); +/** + * Add a custom header to an outgoing susbscription or publish. + * @param ev the LinphoneEvent + * @param name header's name + * @param value the header's value. +**/ +LINPHONE_PUBLIC void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value); + +/** + * Obtain the value of a given header for an incoming subscription. + * @param ev the LinphoneEvent + * @param name header's name + * @return the header's value or NULL if such header doesn't exist. +**/ +LINPHONE_PUBLIC const char *linphone_event_get_custom_header(LinphoneEvent *ev, const char *name); + /** * Terminate an incoming or outgoing subscription that was previously acccepted, or a previous publication. * This function does not unref the object. The core will unref() if it does not need this object anymore. diff --git a/coreapi/private.h b/coreapi/private.h index 4c3459ef8..21a62e334 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -677,6 +677,7 @@ struct _LinphoneEvent{ LinphoneSubscriptionDir dir; LinphoneCore *lc; SalOp *op; + SalCustomHeader *send_custom_headers; LinphoneSubscriptionState subscription_state; LinphonePublishState publish_state; LinphoneReason reason; @@ -685,6 +686,7 @@ struct _LinphoneEvent{ char *name; LinphoneAddress *from; LinphoneAddress *resource_addr; + int expires; bool_t terminating; }; @@ -793,7 +795,7 @@ 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, const char *name); +LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires); LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name); void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 72b8c4fb6..49f0cdc83 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -59,12 +59,13 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, Li break; case LinphoneSubscriptionIncomingReceived: counters->number_of_LinphoneSubscriptionIncomingReceived++; + mgr->lev=lev; if (!mgr->decline_subscribe) linphone_event_accept_subscription(lev); else linphone_event_deny_subscription(lev, LinphoneReasonDeclined); break; - case LinphoneSubscriptionOutoingInit: + case LinphoneSubscriptionOutgoingInit: counters->number_of_LinphoneSubscriptionOutgoingInit++; break; case LinphoneSubscriptionPending: @@ -190,6 +191,66 @@ static void subscribe_test_with_args(bool_t terminated_by_subscriber, RefreshTes linphone_core_manager_destroy(pauline); } +static void subscribe_test_with_args2(bool_t terminated_by_subscriber, RefreshTestType refresh_type) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneContent content={0}; + LinphoneEvent *lev; + int expires= refresh_type!=NoRefresh ? 4 : 600; + MSList* lcs=ms_list_append(NULL,marie->lc); + + lcs=ms_list_append(lcs,pauline->lc); + + if (refresh_type==ManualRefresh){ + lp_config_set_int(marie->lc->config,"sip","refresh_generic_subscribe",0); + } + + content.type="application"; + content.subtype="somexml"; + content.data=(char*)subscribe_content; + content.size=strlen(subscribe_content); + + lev=linphone_core_create_subscribe(marie->lc,pauline->identity,"dodo",expires); + linphone_event_add_custom_header(lev,"My-Header","pouet"); + linphone_event_add_custom_header(lev,"My-Header2","pimpon"); + linphone_event_send_subscribe(lev,&content); + + 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)); + + /*check good receipt of custom headers*/ + CU_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header"),"pouet"); + CU_ASSERT_STRING_EQUAL(linphone_event_get_custom_header(pauline->lev,"My-Header2"),"pimpon"); + + 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 (refresh_type==AutoRefresh){ + wait_for_list(lcs,NULL,0,6000); + CU_ASSERT_TRUE(linphone_event_get_subscription_state(pauline->lev)==LinphoneSubscriptionActive); + }else if (refresh_type==ManualRefresh){ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionExpiring,1,4000)); + linphone_event_update_subscribe(lev,NULL); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,2,2000)); + } + + if (terminated_by_subscriber){ + linphone_event_terminate(lev); + }else{ + CU_ASSERT_PTR_NOT_NULL_FATAL(pauline->lev); + linphone_event_terminate(pauline->lev); + } + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void subscribe_test_terminated_by_subscriber(void){ subscribe_test_with_args(TRUE,NoRefresh); } @@ -205,6 +266,10 @@ static void subscribe_test_refreshed(void){ subscribe_test_with_args(TRUE,AutoRefresh); } +static void subscribe_test_with_custom_header(void){ + subscribe_test_with_args2(TRUE,NoRefresh); +} + static void subscribe_test_manually_refreshed(void){ subscribe_test_with_args(TRUE,ManualRefresh); } @@ -261,6 +326,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 with custom headers", subscribe_test_with_custom_header }, { "Subscribe refreshed", subscribe_test_refreshed }, { "Subscribe manually refreshed", subscribe_test_manually_refreshed }, { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier }, From 362ad2e566a14bb86dd269ea8e21d0236e7ec3c4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 24 Feb 2014 11:33:10 +0100 Subject: [PATCH 278/439] Added JNI wrapper for recently added Publish/Subscribe methods + fix in previous JNI wrapper for encondig in LinphoneContent --- coreapi/linphonecore_jni.cc | 90 ++++++++++++++++++- .../org/linphone/core/LinphoneCore.java | 25 +++++- .../org/linphone/core/LinphoneEvent.java | 26 ++++++ .../org/linphone/core/LinphoneCoreImpl.java | 13 +++ .../org/linphone/core/LinphoneEventImpl.java | 31 +++++++ 5 files changed, 181 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 340210805..c61dbdf8a 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3173,7 +3173,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getUpnpExternalIpaddr * Signature: (JJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; */ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_subscribe(JNIEnv *env, jobject jcore, jlong coreptr, jlong addrptr, - jstring jevname, jint expires, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ + jstring jevname, jint expires, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ LinphoneCore *lc=(LinphoneCore*)coreptr; LinphoneAddress *addr=(LinphoneAddress*)addrptr; LinphoneContent content={0}; @@ -3185,7 +3185,7 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_subscribe(JNIE if (jtype){ content.type=(char*)env->GetStringUTFChars(jtype,NULL); content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); - content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL; + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jencoding,NULL) : NULL; content.data=(void*)env->GetByteArrayElements(jdata,NULL); content.size=env->GetArrayLength(jdata); } @@ -3221,7 +3221,7 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_publish(JNIEnv if (jtype){ content.type=(char*)env->GetStringUTFChars(jtype,NULL); content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); - content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL; + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jencoding,NULL) : NULL; content.data=(void*)env->GetByteArrayElements(jdata,NULL); content.size=env->GetArrayLength(jdata); } @@ -3633,6 +3633,90 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getSubscriptionS return linphone_event_get_subscription_state(ev); } +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createSubscribe(JNIEnv *env, jobject thiz, jlong jcore, jlong jaddr, jstring jeventname, jint expires) { + LinphoneCore *lc = (LinphoneCore*) jcore; + LinphoneCoreData* lcData = (LinphoneCoreData*) linphone_core_get_user_data(lc); + LinphoneAddress *addr = (LinphoneAddress*) jaddr; + LinphoneEvent *event; + jobject jevent = NULL; + const char *event_name = env->GetStringUTFChars(jeventname, NULL); + + event = linphone_core_create_subscribe(lc, addr, event_name, expires); + env->ReleaseStringUTFChars(jeventname, event_name); + if (event) { + jevent = lcData->getEvent(env, event); + } + return jevent; +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_sendSubscribe(JNIEnv *env, jobject thiz, jlong jevent, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding) { + LinphoneContent content = {0}; + if (jtype) { + content.type = (char*) env->GetStringUTFChars(jtype, NULL); + content.subtype = (char*) env->GetStringUTFChars(jsubtype, NULL); + content.encoding = jencoding ? (char*) env->GetStringUTFChars(jencoding, NULL) : NULL; + content.data = (void*) env->GetByteArrayElements(jdata, NULL); + content.size = env->GetArrayLength(jdata); + } + linphone_event_send_subscribe((LinphoneEvent*) jevent, content.type ? &content : NULL); + if (jtype) { + env->ReleaseStringUTFChars(jtype, content.type); + env->ReleaseStringUTFChars(jsubtype, content.subtype); + if (jencoding) env->ReleaseStringUTFChars(jencoding, content.encoding); + env->ReleaseByteArrayElements(jdata, (jbyte*) content.data, JNI_ABORT); + } +} + +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createPublish(JNIEnv *env, jobject thiz, jlong jcore, jlong jaddr, jstring jeventname, jint expires) { + LinphoneCore *lc = (LinphoneCore*) jcore; + LinphoneCoreData* lcData = (LinphoneCoreData*) linphone_core_get_user_data(lc); + LinphoneAddress *addr = (LinphoneAddress*) jaddr; + LinphoneEvent *event; + jobject jevent = NULL; + const char *event_name = env->GetStringUTFChars(jeventname, NULL); + + event = linphone_core_create_publish(lc, addr, event_name, expires); + env->ReleaseStringUTFChars(jeventname, event_name); + if (event) { + jevent = lcData->getEvent(env, event); + } + return jevent; +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_sendPublish(JNIEnv *env, jobject thiz, jlong jevent, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding) { + LinphoneContent content = {0}; + if (jtype) { + content.type = (char*) env->GetStringUTFChars(jtype, NULL); + content.subtype = (char*) env->GetStringUTFChars(jsubtype, NULL); + content.encoding = jencoding ? (char*) env->GetStringUTFChars(jencoding, NULL) : NULL; + content.data = (void*) env->GetByteArrayElements(jdata, NULL); + content.size = env->GetArrayLength(jdata); + } + linphone_event_send_publish((LinphoneEvent*) jevent, content.type ? &content : NULL); + if (jtype) { + env->ReleaseStringUTFChars(jtype, content.type); + env->ReleaseStringUTFChars(jsubtype, content.subtype); + if (jencoding) env->ReleaseStringUTFChars(jencoding, content.encoding); + env->ReleaseByteArrayElements(jdata, (jbyte*) content.data, JNI_ABORT); + } +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_addCustomHeader(JNIEnv *env, jobject thiz, jlong jevent, jstring jname, jstring jvalue) { + const char *name = jname ? env->GetStringUTFChars(jname, NULL) : NULL; + const char *value = jvalue ? env->GetStringUTFChars(jvalue, NULL) : NULL; + linphone_event_add_custom_header((LinphoneEvent*) jevent, name, value); + if (jname) env->ReleaseStringUTFChars(jname, name); + if (jvalue) env->ReleaseStringUTFChars(jvalue, value); +} + +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneEventImpl_getCustomHeader(JNIEnv *env, jobject thiz, jlong jevent, jstring jname) { + const char *name = jname ? env->GetStringUTFChars(jname, NULL) : NULL; + const char *header = linphone_event_get_custom_header((LinphoneEvent*) jevent, name); + jstring jheader = header ? env->NewStringUTF(header) : NULL; + if (jname) env->ReleaseStringUTFChars(jname, name); + return jheader; +} + /* * Class: org_linphone_core_LinphoneEventImpl * Method: unref diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 114150acf..55be3eb24 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1433,7 +1433,30 @@ public interface LinphoneCore { * @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 ); + public LinphoneEvent subscribe(LinphoneAddress resource, String event, int expires, LinphoneContent content); + + /** + * Create an outgoing subscription, specifying the destination resource, the event name, and an optional content body. + * If accepted, the subscription runs for a finite period, but is automatically renewed if not terminated before. + * Unlike linphone_core_subscribe() the subscription isn't sent immediately. It will be send when calling linphone_event_send_subscribe(). + * @param resource the destination resource + * @param event the event name + * @param expires the whished duration of the subscription + * @param body an optional body, may be NULL. + * @return a LinphoneEvent holding the context of the created subcription. + */ + public LinphoneEvent createSubscribe(LinphoneAddress resource, String event, int expires); + + /** + * Create a publish context for an event state. + * After being created, the publish must be sent using linphone_event_send_publish(). + * After expiry, the publication is refreshed unless it is terminated before. + * @param resource the resource uri for the event + * @param event the event name + * @param expires the lifetime of the publication + * @return the LinphoneEvent holding the context of the publish. + */ + public LinphoneEvent createPublish(LinphoneAddress resource, String event, int expires); /** * Publish an event. diff --git a/java/common/org/linphone/core/LinphoneEvent.java b/java/common/org/linphone/core/LinphoneEvent.java index 865200dfd..cdc34d404 100644 --- a/java/common/org/linphone/core/LinphoneEvent.java +++ b/java/common/org/linphone/core/LinphoneEvent.java @@ -68,4 +68,30 @@ public interface LinphoneEvent { * @return */ Object getUserContext(); + + /** + * Add a custom header to an outgoing susbscription or publish. + * @param name header's name + * @param value the header's value. + */ + void addCustomHeader(String name, String value); + + /** + * Obtain the value of a given header for an incoming subscription. + * @param name header's name + * @return the header's value or NULL if such header doesn't exist. + */ + String getCustomHeader(String name); + + /** + * Send a subscription previously created by linphone_core_create_subscribe(). + * @param body optional content to attach with the subscription. + */ + void sendSubscribe(LinphoneContent body); + + /** + * Send a publish created by linphone_core_create_publish(). + * @param body the new data to be published + */ + void sendPublish(LinphoneContent body); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index d3803df22..f7d91c1e9 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -1047,6 +1047,19 @@ class LinphoneCoreImpl implements LinphoneCore { content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getData() : null, content!=null ? content.getEncoding() : null); } + + private native Object createSubscribe(long core, long addr, String event, int expires); + @Override + public LinphoneEvent createSubscribe(LinphoneAddress resource, + String event, int expires) { + return (LinphoneEvent)createSubscribe(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, event, expires); + } + private native Object createPublish(long core, long addr, String event, int expires); + @Override + public LinphoneEvent createPublish(LinphoneAddress resource, + String event, int expires) { + return (LinphoneEvent)createPublish(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, event, expires); + } public void setChatDatabasePath(String path) { setChatDatabasePath(nativePtr, path); diff --git a/java/impl/org/linphone/core/LinphoneEventImpl.java b/java/impl/org/linphone/core/LinphoneEventImpl.java index 9890f7cdf..42d14ef20 100644 --- a/java/impl/org/linphone/core/LinphoneEventImpl.java +++ b/java/impl/org/linphone/core/LinphoneEventImpl.java @@ -1,5 +1,6 @@ package org.linphone.core; + public class LinphoneEventImpl implements LinphoneEvent { private Object mUserContext; private long mNativePtr; @@ -88,4 +89,34 @@ public class LinphoneEventImpl implements LinphoneEvent { unref(mNativePtr); } + private native void addCustomHeader(long ptr, String name, String value); + @Override + public void addCustomHeader(String name, String value) { + addCustomHeader(mNativePtr, name, value); + } + + private native String getCustomHeader(long ptr, String name); + @Override + public String getCustomHeader(String name) { + return getCustomHeader(mNativePtr, name); + } + + private native void sendSubscribe(long ptr, String type, String subtype, byte data [], String encoding); + @Override + public void sendSubscribe(LinphoneContent body) { + if (body != null) + sendSubscribe(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding()); + else + sendSubscribe(mNativePtr, null, null, null, null); + } + + private native void sendPublish(long ptr, String type, String subtype, byte data [], String encoding); + @Override + public void sendPublish(LinphoneContent body) { + if (body != null) + sendPublish(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding()); + else + sendPublish(mNativePtr, null, null, null, null); + } + } From ca5f624bc6480e1a4b35ed0520db18c7fd21bd49 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 24 Feb 2014 14:22:21 +0100 Subject: [PATCH 279/439] Divide huge function in smaller blocks. --- coreapi/bellesip_sal/sal_sdp.c | 408 +++++++++++++++++---------------- include/sal/sal.h | 1 + 2 files changed, 214 insertions(+), 195 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 667c1e22b..8f470c052 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -251,28 +251,223 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr } +static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + PayloadType *pt; + belle_sip_list_t* mime_param_it=NULL; + belle_sdp_mime_parameter_t* mime_param; + belle_sip_list_t* mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc ); + for ( mime_param_it=mime_params + ; mime_param_it!=NULL + ; mime_param_it=mime_param_it->next ) { + mime_param=BELLE_SDP_MIME_PARAMETER ( mime_param_it->data ) + + pt=payload_type_new(); + payload_type_set_number ( pt,belle_sdp_mime_parameter_get_media_format ( mime_param ) ); + pt->clock_rate=belle_sdp_mime_parameter_get_rate ( mime_param ); + pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) ); + pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param ); + payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) ); + stream->payloads=ms_list_append ( stream->payloads,pt ); + stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param ); + ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, + pt->send_fmtp ? pt->send_fmtp : "" ); + } + if ( mime_params ) belle_sip_list_free_with_data ( mime_params,belle_sip_object_unref ); +} + +static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *attribute_it; + const belle_sdp_attribute_t *attribute; + char tmp[256], tmp2[256]; + int valid_count = 0; + int nb; + + memset ( &stream->crypto, 0, sizeof ( stream->crypto ) ); + for ( attribute_it=belle_sdp_media_description_get_attributes ( media_desc ) + ; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; + attribute_it=attribute_it->next ) { + attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data ); + + if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) { + nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s", + &stream->crypto[valid_count].tag, + tmp, + tmp2 ); + ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", + stream->crypto[valid_count].tag, + tmp, + tmp2 ); + if ( nb == 3 ) { + if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ) + stream->crypto[valid_count].algo = 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 ); +} + +static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *attribute_it; + const belle_sdp_attribute_t *attribute; + const char *att_name; + const char *value; + int nb_ice_candidates = 0; + + for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { + attribute=(belle_sdp_attribute_t*)attribute_it->data; + att_name = belle_sdp_attribute_get_name(attribute); + value = belle_sdp_attribute_get_value(attribute); + + if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { + SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; + int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d", + candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port, + candidate->type, candidate->raddr, &candidate->rport); + if ((nb == 6) || (nb == 8)) nb_ice_candidates++; + else memset(candidate, 0, sizeof(*candidate)); + } else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) { + SalIceRemoteCandidate candidate; + unsigned int componentID; + int offset; + const char *ptr = value; + const char *endptr = value + strlen(ptr); + while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) { + if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) { + SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1]; + strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)); + remote_candidate->port = candidate.port; + } + ptr += offset; + if (ptr < endptr) { + if (ptr[offset] == ' ') ptr += 1; + } else break; + } + } else if ((keywordcmp("ice-ufrag", att_name) == 0) && (value != NULL)) { + strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)); + } else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) { + strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd)); + } else if (keywordcmp("ice-mismatch", att_name) == 0) { + stream->ice_mismatch = TRUE; + } + } +} + +static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, belle_sdp_media_description_t *media_desc) { + SalStreamDescription *stream; + belle_sdp_connection_t* cnx; + belle_sdp_media_t* media; + const belle_sdp_attribute_t* attribute; + const char* value; + const char *mtype,*proto; + + stream=&md->streams[md->n_total_streams]; + media=belle_sdp_media_description_get_media ( media_desc ); + + memset ( stream,0,sizeof ( *stream ) ); + + proto = belle_sdp_media_get_protocol ( media ); + stream->proto=SalProtoUnknown; + if ( proto ) { + if ( strcasecmp ( proto,"RTP/AVP" ) ==0 ) + stream->proto=SalProtoRtpAvp; + else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) { + stream->proto=SalProtoRtpSavp; + } + } + if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { + strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ),sizeof ( stream->rtp_addr ) ); + } + + stream->rtp_port=belle_sdp_media_get_media_port ( media ); + + if ( stream->rtp_port > 0 ) + md->n_active_streams++; + + mtype = belle_sdp_media_get_media_type ( media ); + if ( strcasecmp ( "audio", mtype ) == 0 ) { + stream->type=SalAudio; + } else if ( strcasecmp ( "video", mtype ) == 0 ) { + stream->type=SalVideo; + } else { + stream->type=SalOther; + strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 ); + } + + if ( belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ) >0 ) { + stream->bandwidth=belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ); + } + + if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) { + stream->dir=SalStreamSendRecv; + } else if ( belle_sdp_media_description_get_attribute ( media_desc,"sendonly" ) ) { + stream->dir=SalStreamSendOnly; + } else if ( belle_sdp_media_description_get_attribute ( media_desc,"recvonly" ) ) { + stream->dir=SalStreamRecvOnly; + } else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) { + stream->dir=SalStreamInactive; + } else { + stream->dir=md->dir; /*takes default value if not present*/ + } + + /* Get media payload types */ + sdp_parse_payload_types(media_desc, stream); + + /* Get media specific RTCP attribute */ + stream->rtcp_port = stream->rtp_port + 1; + snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr); + attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp"); + if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){ + char tmp[256]; + int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp); + if (nb == 1) { + /* SDP rtcp attribute only contains the port */ + } else if (nb == 2) { + strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); + } else { + ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb); + } + } + + /* Read crypto lines if any */ + if ( stream->proto == SalProtoRtpSavp ) { + sdp_parse_media_crypto_parameters(media_desc, stream); + } + + /* Get ICE candidate attributes if any */ + sdp_parse_ice_media_parameters(media_desc, stream); + + md->n_total_streams++; + return stream; +} + + int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) { belle_sdp_connection_t* cnx; belle_sip_list_t* media_desc_it; belle_sdp_media_description_t* media_desc; belle_sdp_session_name_t *sname; - const char *mtype,*proto; - SalStreamDescription *stream; - belle_sdp_media_t* media; - belle_sip_list_t* mime_params=NULL; - belle_sip_list_t* mime_param_it=NULL; - belle_sdp_mime_parameter_t* mime_param; - PayloadType *pt; - belle_sip_list_t* attribute_it; - const belle_sdp_attribute_t* attribute; - int valid_count = 0; - char tmp[256], tmp2[256]; - int nb=0; - SalStreamDir stream_dir=SalStreamSendRecv; const char* value; desc->n_active_streams = 0; desc->n_total_streams = 0; + desc->dir = SalStreamSendRecv; if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) ); @@ -287,13 +482,13 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S /*in some very rare case, session attribute may set stream dir*/ if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) { - stream_dir=SalStreamSendRecv; + desc->dir=SalStreamSendRecv; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) { - stream_dir=SalStreamSendOnly; + desc->dir=SalStreamSendOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) { - stream_dir=SalStreamRecvOnly; + desc->dir=SalStreamRecvOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) { - stream_dir=SalStreamInactive; + desc->dir=SalStreamInactive; } /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ @@ -309,189 +504,12 @@ 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; - if (desc->n_total_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){ ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->n_total_streams); break; } - media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); - stream=&desc->streams[desc->n_total_streams]; - media=belle_sdp_media_description_get_media ( media_desc ); - - memset ( stream,0,sizeof ( *stream ) ); - - proto = belle_sdp_media_get_protocol ( media ); - stream->proto=SalProtoUnknown; - if ( proto ) { - if ( strcasecmp ( proto,"RTP/AVP" ) ==0 ) - stream->proto=SalProtoRtpAvp; - else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) { - stream->proto=SalProtoRtpSavp; - } - } - if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { - strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ),sizeof ( stream->rtp_addr ) ); - } - - stream->rtp_port=belle_sdp_media_get_media_port ( media ); - - if ( stream->rtp_port > 0 ) - desc->n_active_streams++; - - mtype = belle_sdp_media_get_media_type ( media ); - if ( strcasecmp ( "audio", mtype ) == 0 ) { - stream->type=SalAudio; - } else if ( strcasecmp ( "video", mtype ) == 0 ) { - stream->type=SalVideo; - } else { - stream->type=SalOther; - strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 ); - } - - if ( belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ) >0 ) { - stream->bandwidth=belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ); - } - - - if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) { - stream->dir=SalStreamSendRecv; - } else if ( belle_sdp_media_description_get_attribute ( media_desc,"sendonly" ) ) { - stream->dir=SalStreamSendOnly; - } else if ( belle_sdp_media_description_get_attribute ( media_desc,"recvonly" ) ) { - stream->dir=SalStreamRecvOnly; - } else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) { - stream->dir=SalStreamInactive; - } else { - stream->dir=stream_dir; /*takes default value if not present*/ - } - - /* for each payload type */ - mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc ); - for ( mime_param_it=mime_params - ; mime_param_it!=NULL - ; mime_param_it=mime_param_it->next ) { - mime_param=BELLE_SDP_MIME_PARAMETER ( mime_param_it->data ) - - pt=payload_type_new(); - payload_type_set_number ( pt,belle_sdp_mime_parameter_get_media_format ( mime_param ) ); - pt->clock_rate=belle_sdp_mime_parameter_get_rate ( mime_param ); - pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) ); - pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param ); - payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) ); - stream->payloads=ms_list_append ( stream->payloads,pt ); - stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param ); - ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, - pt->send_fmtp ? pt->send_fmtp : "" ); - } - if ( mime_params ) belle_sip_list_free_with_data ( mime_params,belle_sip_object_unref ); - - - /* Get media specific RTCP attribute */ - stream->rtcp_port = stream->rtp_port + 1; - snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr); - attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp"); - if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){ - char tmp[256]; - int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp); - if (nb == 1) { - /* SDP rtcp attribute only contains the port */ - } else if (nb == 2) { - strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); - } else { - ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb); - } - } - - /* read crypto lines if any */ - if ( stream->proto == SalProtoRtpSavp ) { - valid_count=0; - memset ( &stream->crypto, 0, sizeof ( stream->crypto ) ); - for ( attribute_it=belle_sdp_media_description_get_attributes ( media_desc ) - ; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; - attribute_it=attribute_it->next ) { - attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data ); - - if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) { - nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s", - &stream->crypto[valid_count].tag, - tmp, - tmp2 ); - ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", - stream->crypto[valid_count].tag, - tmp, - tmp2 ); - if ( nb == 3 ) { - if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ) - stream->crypto[valid_count].algo = AES_128_SHA1_80; - else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 ) - stream->crypto[valid_count].algo = AES_128_SHA1_32; - else { - ms_warning ( "Failed to parse crypto-algo: '%s'", tmp ); - stream->crypto[valid_count].algo = 0; - } - if ( stream->crypto[valid_count].algo ) { - strncpy ( stream->crypto[valid_count].master_key, tmp2, 41 ); - stream->crypto[valid_count].master_key[40] = '\0'; - ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", - stream->crypto[valid_count].tag, - tmp, - stream->crypto[valid_count].master_key ); - valid_count++; - } - } else { - ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb ); - } - } - } - ms_message ( "Found: %d valid crypto lines", valid_count ); - } - - /* Get ICE candidate attributes if any */ - for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { - const char *att_name; - attribute=(belle_sdp_attribute_t*)attribute_it->data; - att_name=belle_sdp_attribute_get_name(attribute); - value=belle_sdp_attribute_get_value(attribute); - if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { - SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; - int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d", - candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port, - candidate->type, candidate->raddr, &candidate->rport); - if ((nb == 6) || (nb == 8)) nb_ice_candidates++; - else memset(candidate, 0, sizeof(*candidate)); - } else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) { - SalIceRemoteCandidate candidate; - unsigned int componentID; - int offset; - const char *ptr = value; - const char *endptr=value+strlen(ptr); - while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) { - if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) { - SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1]; - strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)); - remote_candidate->port = candidate.port; - } - ptr += offset; - if (ptrice_ufrag, value, sizeof(stream->ice_ufrag)); - } else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) { - strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd)); - } else if (keywordcmp("ice-mismatch", att_name) == 0) { - stream->ice_mismatch = TRUE; - } - } - desc->n_total_streams++; + sdp_to_stream_description(desc, media_desc); } return 0; } - - - - - diff --git a/include/sal/sal.h b/include/sal/sal.h index 8ff57dc12..3deb3ddb4 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -211,6 +211,7 @@ typedef struct SalMediaDescription{ int bandwidth; unsigned int session_ver; unsigned int session_id; + SalStreamDir dir; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; From e9b444c3c61b543eb5c69272486d362e00f91345 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 25 Feb 2014 11:20:07 +0100 Subject: [PATCH 280/439] Updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 77b6e16c9..6a70456f1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 77b6e16c9ef07fdbb741d220c89e749ff746d654 +Subproject commit 6a70456f1207b7bcd738fc4810fc41e00f2e32e7 From ce7404581abd927361fcd6b73b40255a3081f904 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 26 Feb 2014 12:31:51 +0100 Subject: [PATCH 281/439] Allow null String value in jni wrapper for LpConfig.setString method --- 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 c61dbdf8a..9d5461147 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3318,11 +3318,11 @@ extern "C" void Java_org_linphone_core_LpConfigImpl_setString(JNIEnv *env, jobje jstring section, jstring key, jstring value) { const char *csection = env->GetStringUTFChars(section, NULL); const char *ckey = env->GetStringUTFChars(key, NULL); - const char *cvalue = env->GetStringUTFChars(value, NULL); + const char *cvalue = value ? env->GetStringUTFChars(value, NULL) : NULL; lp_config_set_string((LpConfig *)lpc, csection, ckey, cvalue); env->ReleaseStringUTFChars(section, csection); env->ReleaseStringUTFChars(key, ckey); - env->ReleaseStringUTFChars(value, cvalue); + if (value) env->ReleaseStringUTFChars(value, cvalue); } extern "C" jstring Java_org_linphone_core_LpConfigImpl_getString(JNIEnv *env, jobject thiz, jlong lpc, From f3ca28fe647038105a28cff4deb59098a59b0811 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 26 Feb 2014 16:36:21 +0100 Subject: [PATCH 282/439] Fix CMake install paths. --- coreapi/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 85a03061e..2fa09d9ae 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -123,9 +123,10 @@ set_target_properties(linphone PROPERTIES VERSION 3.7.0 SOVERSION 5) target_link_libraries(linphone ${LIBS}) install(TARGETS linphone - DESTINATION ${LIB_INSTALL_DIR} - PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) file(GLOB HEADER_FILES "*.h") @@ -137,7 +138,7 @@ install(FILES ${HEADER_FILES} if(WIN32) if(CMAKE_BUILD_TYPE STREQUAL "Debug") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/linphone.pdb - DESTINATION ${LIB_INSTALL_DIR} + DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() From c0bd6fb61e03a3592ed4e3164f1234f68372b6b7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 27 Feb 2014 10:28:10 +0100 Subject: [PATCH 283/439] JNI wrapper for accept_early_media methods --- coreapi/linphonecore_jni.cc | 15 +++++++++++++ .../org/linphone/core/LinphoneCore.java | 22 +++++++++++++++++++ .../org/linphone/core/LinphoneCoreImpl.java | 14 ++++++++++++ 3 files changed, 51 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 9d5461147..036e73c87 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1015,6 +1015,21 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_deferCallUpdate(JNIEnv * linphone_core_defer_call_update((LinphoneCore*)lc,(LinphoneCall*)call); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_acceptEarlyMedia(JNIEnv *env, jobject thiz, jlong lc, jlong c) { + LinphoneCore *core = (LinphoneCore *)lc; + LinphoneCall *call = (LinphoneCall *)c; + int ret = linphone_core_accept_early_media(core, call); + return (jboolean) ret == 0; +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_acceptEarlyMediaWithParams(JNIEnv *env, jobject thiz, jlong lc, jlong c, jlong params) { + LinphoneCore *core = (LinphoneCore *)lc; + LinphoneCall *call = (LinphoneCall *)c; + const LinphoneCallParams *call_params = (LinphoneCallParams *) params; + int ret = linphone_core_accept_early_media_with_params(core, call, call_params); + return (jboolean) ret == 0; +} + extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getCallLog( JNIEnv* env ,jobject thiz ,jlong lc diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 55be3eb24..03d946a4e 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1496,4 +1496,26 @@ public interface LinphoneCore { * @returns 1 if migration was done, 0 if not done because unnecessary or already done, -1 in case of error. */ public int migrateToMultiTransport(); + + /** + * When receiving an incoming, accept to start a media session as early-media. + * This means the call is not accepted but audio & video streams can be established if the remote party supports early media. + * However, unlike after call acceptance, mic and camera input are not sent during early-media, though received audio & video are played normally. + * The call can then later be fully accepted using linphone_core_accept_call() or linphone_core_accept_call_with_params(). + * @param lc the linphonecore + * @param call the call + * @param params the call params, can be NULL. + * @return true if successful, false otherwise. + */ + public boolean acceptEarlyMedia(LinphoneCall call); + + /** + * Accept an early media session for an incoming call. + * This is identical as calling linphone_core_accept_early_media_with_params() with NULL call parameters. + * @see linphone_core_accept_early_media_with_params() + * @param lc the core + * @param call the incoming call + * @return true if successful, false otherwise. + */ + public boolean acceptEarlyMediaWithParams(LinphoneCall call, LinphoneCallParams params); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index f7d91c1e9..9b885a6b2 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -1115,4 +1115,18 @@ class LinphoneCoreImpl implements LinphoneCore { public int migrateToMultiTransport() { return migrateToMultiTransport(nativePtr); } + + private native boolean acceptEarlyMedia(long lc, long call); + @Override + public boolean acceptEarlyMedia(LinphoneCall call) { + return acceptEarlyMedia(nativePtr, getCallPtr(call)); + } + + private native boolean acceptEarlyMediaWithParams(long lc, long call, long params); + @Override + public boolean acceptEarlyMediaWithParams(LinphoneCall call, + LinphoneCallParams params) { + long ptrParams = params != null ? ((LinphoneCallParamsImpl) params).nativePtr : 0; + return acceptEarlyMediaWithParams(nativePtr, getCallPtr(call), ptrParams); + } } From 3cd4eb5e75c6f9606ead1a38e4708b8031c44191 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 27 Feb 2014 10:50:13 +0100 Subject: [PATCH 284/439] Always build remote_provisioning.c for Android --- build/android/Android.mk | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index bd59cb4e3..47098be79 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -61,7 +61,10 @@ LOCAL_SRC_FILES := \ message_storage.c \ info.c \ event.c \ - xml.c + xml.c \ + xml2lpc.c \ + lpc2xml.c \ + remote_provisioning.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" @@ -205,14 +208,6 @@ ifeq ($(BUILD_SRTP),1) LOCAL_SHARED_LIBRARIES += libsrtp endif -ifeq ($(BUILD_REMOTE_PROVISIONING),1) -LOCAL_SRC_FILES += ../coreapi/xml2lpc.c \ - ../tools/xml2lpc_jni.cc \ - ../coreapi/lpc2xml.c \ - ../tools/lpc2xml_jni.cc \ - ../coreapi/remote_provisioning.c -endif - ifeq ($(BUILD_SQLITE),1) LOCAL_CFLAGS += -DMSG_STORAGE_ENABLED LOCAL_STATIC_LIBRARIES += liblinsqlite From 3a3f331ca30c0cffee9bfaab7edf66d148f968d1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 27 Feb 2014 11:22:19 +0100 Subject: [PATCH 285/439] JNI wrapper for LinphoneCallParams getSentVideoSize and getReceivedVideoSize methods --- coreapi/linphonecore_jni.cc | 18 ++++++++++++++++ .../org/linphone/core/LinphoneCallParams.java | 12 +++++++++++ java/common/org/linphone/core/VideoSize.java | 4 +++- .../linphone/core/LinphoneCallParamsImpl.java | 21 ++++++++++++++++++- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 036e73c87..cbf3a1bd7 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2660,6 +2660,24 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setRecordFile(JNIE }else linphone_call_params_set_record_file((LinphoneCallParams*)lcp,NULL); } +extern "C" jintArray Java_org_linphone_core_LinphoneCallParamsImpl_getSentVideoSize(JNIEnv *env, jobject thiz, jlong lcp) { + const LinphoneCallParams *params = (LinphoneCallParams *) lcp; + MSVideoSize vsize = linphone_call_params_get_sent_video_size(params); + jintArray arr = env->NewIntArray(2); + int tVsize [2]= {vsize.width,vsize.height}; + env->SetIntArrayRegion(arr, 0, 2, tVsize); + return arr; +} + +extern "C" jintArray Java_org_linphone_core_LinphoneCallParamsImpl_getReceivedVideoSize(JNIEnv *env, jobject thiz, jlong lcp) { + const LinphoneCallParams *params = (LinphoneCallParams *) lcp; + MSVideoSize vsize = linphone_call_params_get_received_video_size(params); + jintArray arr = env->NewIntArray(2); + int tVsize [2]= {vsize.width,vsize.height}; + env->SetIntArrayRegion(arr, 0, 2, tVsize); + return arr; +} + extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_destroy(JNIEnv *env, jobject thiz, jlong lc){ return linphone_call_params_destroy((LinphoneCallParams*)lc); } diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java index 86dd1ea4b..b226077cd 100644 --- a/java/common/org/linphone/core/LinphoneCallParams.java +++ b/java/common/org/linphone/core/LinphoneCallParams.java @@ -116,4 +116,16 @@ public interface LinphoneCallParams { * @return the session name **/ String getSessionName(); + + /** + * Gets the size of the video that is sent. + * @return The sent video size. + */ + VideoSize getSentVideoSize(); + + /** + * Gets the size of the video that is received. + * @return The received video size. + */ + VideoSize getReceivedVideoSize(); } diff --git a/java/common/org/linphone/core/VideoSize.java b/java/common/org/linphone/core/VideoSize.java index b9b3e0710..6bba95e74 100644 --- a/java/common/org/linphone/core/VideoSize.java +++ b/java/common/org/linphone/core/VideoSize.java @@ -78,7 +78,9 @@ public final class VideoSize { return true; } - + public String toDisplayableString() { + return width + "x" + height; + } public String toString() { return "width = "+width + " height = " + height; } diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java index 9c3fe9468..a3c6425b8 100644 --- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java @@ -130,5 +130,24 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams { public String getSessionName() { return getSessionName(nativePtr); } - + + private native int[] getSentVideoSize(long nativePtr); + @Override + public VideoSize getSentVideoSize() { + int[] nativeSize = getSentVideoSize(nativePtr); + VideoSize vSize = new VideoSize(); + vSize.width = nativeSize[0]; + vSize.height = nativeSize[1]; + return vSize; + } + + private native int[] getReceivedVideoSize(long nativePtr); + @Override + public VideoSize getReceivedVideoSize() { + int[] nativeSize = getReceivedVideoSize(nativePtr); + VideoSize vSize = new VideoSize(); + vSize.width = nativeSize[0]; + vSize.height = nativeSize[1]; + return vSize; + } } From d5dbe3eb662c8e962e1657d741793e3906861ca8 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 27 Feb 2014 15:47:54 +0100 Subject: [PATCH 286/439] Fix last 2 tests failing for Android because sound card was opened twice --- tester/call_tester.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 3f84eaf27..8eb9f3adc 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1081,7 +1081,7 @@ static void early_media_call(void) { } static void early_media_call_with_ringing(void){ - + char hellopath[256]; LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc"); MSList* lcs = NULL; @@ -1092,6 +1092,11 @@ static void early_media_call_with_ringing(void){ /* Marie calls Pauline, and after the call has rung, transitions to an early_media session */ + + /*use playfile for callee to avoid locking on capture card*/ + linphone_core_use_files (pauline->lc,TRUE); + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + linphone_core_set_play_file(pauline->lc,hellopath); marie_call = linphone_core_invite_address(marie->lc, pauline->identity); @@ -1450,6 +1455,7 @@ static void call_established_with_rejected_incoming_reinvite(void) { } static void call_redirect(void){ + char hellopath[256]; LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc"); LinphoneCoreManager* laure = linphone_core_manager_new("laure_rc"); @@ -1463,6 +1469,13 @@ static void call_redirect(void){ /* Marie calls Pauline, which will redirect the call to Laure via a 302 */ + + /*use playfile for callee to avoid locking on capture card*/ + linphone_core_use_files (pauline->lc,TRUE); + linphone_core_use_files (laure->lc,TRUE); + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + linphone_core_set_play_file(pauline->lc,hellopath); + linphone_core_set_play_file(laure->lc,hellopath); marie_call = linphone_core_invite_address(marie->lc, pauline->identity); From 9915ab662dd58b4dc736eca90f89466ded059058 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 28 Feb 2014 10:13:38 +0100 Subject: [PATCH 287/439] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6a70456f1..2a607212b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6a70456f1207b7bcd738fc4810fc41e00f2e32e7 +Subproject commit 2a607212bd3ae85cb02cb3dfc9c305bda64f57dc From 24ead1f24fe61299a89f82f13a9ba12c11ed9731 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 28 Feb 2014 10:52:53 +0100 Subject: [PATCH 288/439] Added option to remove provisioning uri once it has been successfully applied --- coreapi/linphonecore.c | 5 +++++ coreapi/linphonecore.h | 6 ++++++ coreapi/remote_provisioning.c | 10 ++++++---- tester/rcfiles/marie_transient_remote_rc | 2 ++ tester/remote_provisioning_tester.c | 12 +++++++++++- 5 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tester/rcfiles/marie_transient_remote_rc diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 70caaa6c6..ca770b15e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1270,6 +1270,11 @@ void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState if (lc->vtable.configuring_status) lc->vtable.configuring_status(lc, state, message); + if (state == LinphoneConfiguringSuccessful) { + if (linphone_core_is_provisioning_transient(lc) == TRUE) + linphone_core_set_provisioning_uri(lc, NULL); + } + linphone_core_start(lc); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f230e6657..f70a13ad0 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2309,6 +2309,12 @@ LINPHONE_PUBLIC void linphone_core_set_provisioning_uri(LinphoneCore *lc, const **/ LINPHONE_PUBLIC const char* linphone_core_get_provisioning_uri(const LinphoneCore *lc); +/** + * Gets if the provisioning URI should be removed after it's been applied successfully + * @param lc the linphone core + * @return TRUE if the provisioning URI should be removed, FALSE otherwise + */ +LINPHONE_PUBLIC bool_t linphone_core_is_provisioning_transient(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_migrate_to_multi_transport(LinphoneCore *lc); #ifdef __cplusplus diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c index 1749fa317..7deb4d5e6 100644 --- a/coreapi/remote_provisioning.c +++ b/coreapi/remote_provisioning.c @@ -99,12 +99,14 @@ int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char return 0; } -void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char*uri){ - if (linphone_core_ready(lc)){ - lp_config_set_string(lc->config,"misc","config-uri",uri); - } +void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char *uri) { + lp_config_set_string(lc->config,"misc","config-uri",uri); } const char*linphone_core_get_provisioning_uri(const LinphoneCore *lc){ return lp_config_get_string(lc->config,"misc","config-uri",NULL); } + +bool_t linphone_core_is_provisioning_transient(LinphoneCore *lc) { + return lp_config_get_int(lc->config, "misc", "transient_provisioning", 0) == 1; +} diff --git a/tester/rcfiles/marie_transient_remote_rc b/tester/rcfiles/marie_transient_remote_rc new file mode 100644 index 000000000..138da3cc1 --- /dev/null +++ b/tester/rcfiles/marie_transient_remote_rc @@ -0,0 +1,2 @@ +[misc] +config-uri=http://smtp.linphone.org/marie_transient_xml diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 1430c31b3..15e2ff05e 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -48,6 +48,15 @@ static void remote_provisioning_http(void) { linphone_core_manager_destroy(marie); } +static void remote_provisioning_transient(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_transient_remote_rc", FALSE); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneRegistrationOk,1)); + CU_ASSERT_TRUE(linphone_core_is_provisioning_transient(marie->lc) == TRUE); + CU_ASSERT_TRUE(linphone_core_get_provisioning_uri(marie->lc) == NULL); + linphone_core_manager_destroy(marie); +} + static void remote_provisioning_https(void) { LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_https_rc", FALSE); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); @@ -72,7 +81,8 @@ test_t remote_provisioning_tests[] = { { "Remote provisioning successful behind http", remote_provisioning_http }, { "Remote provisioning successful behind https", remote_provisioning_https }, { "Remote provisioning 404 not found", remote_provisioning_not_found }, - { "Remote provisioning invalid", remote_provisioning_invalid } + { "Remote provisioning invalid", remote_provisioning_invalid }, + { "Remote provisioning transient successful", remote_provisioning_transient } }; test_suite_t remote_provisioning_test_suite = { From 645447dcef7679a54b080501ab3905ad00f4c82f Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Fri, 28 Feb 2014 12:52:52 +0100 Subject: [PATCH 289/439] Simplify client certificate configuration. We can only handle one client certificate: allow setting direct path to the chain and key files. --- coreapi/callbacks.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 033b1660b..1da9b56a9 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -924,25 +924,9 @@ static void ping_reply(SalOp *op){ } } -static const char *get_client_cert_path(LinphoneCore *lc) { - static char cldir[200] = {0}; - #ifdef HAVE_GETENV - if (!cldir[0]) { - static char default_path[200] = {0}; - snprintf(default_path, sizeof(default_path), "%s%s", getenv("HOME"), "/linphone_certs"); - snprintf(cldir, sizeof(cldir), "%s", lp_config_get_string(lc->config,"sip","client_certificates_dir", default_path)); - } - #endif - return cldir; -} static bool_t fill_auth_info_with_client_certificate(LinphoneCore *lc, SalAuthInfo* sai) { - char chain_file[200]; - char key_file[200]; - const char *path = get_client_cert_path(lc); - - snprintf(chain_file, sizeof(chain_file), "%s%s", path, "/chain.pem"); - - snprintf(key_file, sizeof(key_file), "%s%s", path, "/key.pem"); + const char *chain_file = lp_config_get_string(lc->config,"sip","client_cert_chain", 0); + const char *key_file = lp_config_get_string(lc->config,"sip","client_cert_key", 0);; #ifndef WIN32 { From 028f4c550b267c2801cfc7fd93dcb3c8d237a84d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 28 Feb 2014 16:07:59 +0100 Subject: [PATCH 290/439] Updated ms2 to fix NPE on some Android --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2a607212b..0e6be4c7c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2a607212bd3ae85cb02cb3dfc9c305bda64f57dc +Subproject commit 0e6be4c7cad7ce3d3cb4feed9a6ad52439ba365e From 1af4a7c091280cbed0982f4180b768db612a4a71 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 28 Feb 2014 16:30:11 +0100 Subject: [PATCH 291/439] improve SDP<->SalMediaDescription conversion and offer answer algorithm --- coreapi/bellesip_sal/sal_impl.c | 6 +++++ coreapi/bellesip_sal/sal_sdp.c | 24 ++++++++++--------- coreapi/linphonecall.c | 2 ++ coreapi/offeranswer.c | 42 ++++++++++++++++++++++++++++----- coreapi/proxy.c | 4 +++- coreapi/sal.c | 10 ++++++++ include/sal/sal.h | 14 ++++++++--- 7 files changed, 81 insertions(+), 21 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 62610f406..bfe90e035 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -947,6 +947,12 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ return belle_sip_random_bytes(ret,size); } +unsigned int sal_get_random(void){ + unsigned int ret=0; + belle_sip_random_bytes((unsigned char*)&ret,4); + return ret; +} + belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) { belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name); diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 8f470c052..1f0da7fb0 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -87,7 +87,7 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMedia rtp_port=stream->rtp_port; rtcp_port=stream->rtcp_port; - media_desc = belle_sdp_media_description_create ( sal_stream_type_to_string ( stream->type ) + media_desc = belle_sdp_media_description_create ( sal_stream_description_get_type_as_string(stream) ,stream->rtp_port ,1 ,sal_media_proto_to_string ( stream->proto ) @@ -351,7 +351,7 @@ static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_ 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)); + strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)-1); remote_candidate->port = candidate.port; } ptr += offset; @@ -360,9 +360,9 @@ static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_ } else break; } } else if ((keywordcmp("ice-ufrag", att_name) == 0) && (value != NULL)) { - strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)); + strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)-1); } else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) { - strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd)); + strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd) -1); } else if (keywordcmp("ice-mismatch", att_name) == 0) { stream->ice_mismatch = TRUE; } @@ -383,16 +383,18 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, memset ( stream,0,sizeof ( *stream ) ); proto = belle_sdp_media_get_protocol ( media ); - stream->proto=SalProtoUnknown; + stream->proto=SalProtoOther; if ( proto ) { if ( strcasecmp ( proto,"RTP/AVP" ) ==0 ) stream->proto=SalProtoRtpAvp; else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) { stream->proto=SalProtoRtpSavp; + }else{ + strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1); } } if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { - strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ),sizeof ( stream->rtp_addr ) ); + strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ), sizeof ( stream->rtp_addr ) -1 ); } stream->rtp_port=belle_sdp_media_get_media_port ( media ); @@ -439,7 +441,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, if (nb == 1) { /* SDP rtcp attribute only contains the port */ } else if (nb == 2) { - strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); + strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)-1); } else { ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb); } @@ -470,10 +472,10 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S desc->dir = SalStreamSendRecv; if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { - strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) ); + strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) -1 ); } if ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){ - strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name)); + strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name) - 1); } if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) { @@ -493,10 +495,10 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag"); - if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag)); + if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); - if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)); + if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)-1); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); if (value) desc->ice_lite = TRUE; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 820ee3427..8699b1ec9 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -293,6 +293,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->n_active_streams=1; 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)); + strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1); 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) ? @@ -309,6 +310,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * if (call->params.has_video){ md->n_active_streams++; + strncpy(md->streams[0].name,"Video",sizeof(md->streams[0].name)-1); md->streams[1].rtp_port=call->video_port; md->streams[1].rtcp_port=call->video_port+1; md->streams[1].proto=md->streams[0].proto; diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 42d856310..88a62535d 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -262,6 +262,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, result->ice_completed = local_cap->ice_completed; memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates)); memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates)); + strcpy(result->name,local_cap->name); } /** @@ -291,6 +292,35 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, return 0; } +static bool_t local_stream_not_already_used(const SalMediaDescription *result, const SalStreamDescription *stream){ + int i; + for(i=0;in_total_streams;++i){ + const SalStreamDescription *ss=&result->streams[i]; + if (strcmp(ss->name,stream->name)==0){ + ms_message("video stream already used in answer"); + return FALSE; + } + } + return TRUE; +} + +/*in answering mode, we consider that if we are able to make SAVP, then we can do AVP as well*/ +static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote){ + if (local==remote) return TRUE; + if (remote==SalProtoRtpAvp && local==SalProtoRtpSavp) return TRUE; + return FALSE; +} + +static const SalStreamDescription *find_local_matching_stream(const SalMediaDescription *result, const SalMediaDescription *local_capabilities, const SalStreamDescription *remote_stream){ + int i; + for(i=0;in_active_streams;++i){ + const SalStreamDescription *ss=&local_capabilities->streams[i]; + if (ss->type==remote_stream->type && proto_compatible(ss->proto,remote_stream->proto) + && local_stream_not_already_used(result,ss)) return ss; + } + return NULL; +} + /** * Returns a media description to run the streams with, based on the local capabilities and * and the received offer. @@ -305,17 +335,14 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities result->n_active_streams=0; for(i=0;in_total_streams;++i){ rs=&remote_offer->streams[i]; - if (rs->proto!=SalProtoUnknown){ - ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); - /* if matching failed, and remote proposes Avp only, ask for local Savp streams */ - if (!ls && rs->proto == SalProtoRtpAvp) { - ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,SalProtoRtpSavp,rs->type); - } + if (rs->proto!=SalProtoOther){ + ls=find_local_matching_stream(result,local_capabilities,rs); }else ms_warning("Unknown protocol for mline %i, declining",i); if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); if (result->streams[i].rtp_port!=0) result->n_active_streams++; }else { + ms_message("Declining mline %i, no corresponding stream in local capabilities description.",i); /* create an inactive stream for the answer, as there where no matching stream in local capabilities */ result->streams[i].dir=SalStreamInactive; result->streams[i].rtp_port=0; @@ -324,6 +351,9 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities if (rs->type==SalOther){ strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1); } + if (rs->proto==SalProtoOther){ + strncpy(result->streams[i].proto_other,rs->proto_other,sizeof(rs->proto_other)-1); + } } } result->n_total_streams=i; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 6bc8e5588..8d485b910 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -42,10 +42,12 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ } static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj){ + const char *dial_prefix; memset(obj,0,sizeof(LinphoneProxyConfig)); obj->magic=linphone_proxy_config_magic; obj->expires=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"reg_expires",3600); - obj->dial_prefix=ms_strdup(LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",'\0')); + dial_prefix=LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",NULL); + if (dial_prefix) obj->dial_prefix=ms_strdup(dial_prefix); 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); } diff --git a/coreapi/sal.c b/coreapi/sal.c index 46f7325df..6f2256ac9 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -498,6 +498,11 @@ const char* sal_stream_type_to_string(SalStreamType type) { } } +const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc){ + if (desc->type==SalOther) return desc->typeother; + else return sal_stream_type_to_string(desc->type); +} + const char* sal_media_proto_to_string(SalMediaProto type) { switch (type) { case SalProtoRtpAvp:return "RTP/AVP"; @@ -506,6 +511,11 @@ const char* sal_media_proto_to_string(SalMediaProto type) { } } +const char *sal_stream_description_get_proto_as_string(const SalStreamDescription *desc){ + if (desc->proto==SalProtoOther) return desc->proto_other; + else return sal_media_proto_to_string(desc->proto); +} + const char* sal_stream_dir_to_string(SalStreamDir type) { switch (type) { diff --git a/include/sal/sal.h b/include/sal/sal.h index 3deb3ddb4..0fa968eb2 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -121,9 +121,9 @@ typedef enum { const char* sal_stream_type_to_string(SalStreamType type); typedef enum{ - SalProtoUnknown, SalProtoRtpAvp, - SalProtoRtpSavp + SalProtoRtpSavp, + SalProtoOther }SalMediaProto; const char* sal_media_proto_to_string(SalMediaProto type); @@ -177,9 +177,11 @@ typedef struct SalSrtpCryptoAlgo { #define SAL_CRYPTO_ALGO_MAX 4 typedef struct SalStreamDescription{ + char name[16]; /*unique name of stream, in order to ease offer/answer model algorithm*/ SalMediaProto proto; SalStreamType type; char typeother[32]; + char proto_other[32]; char rtp_addr[64]; char rtcp_addr[64]; int rtp_port; @@ -197,9 +199,13 @@ typedef struct SalStreamDescription{ char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; bool_t ice_mismatch; bool_t ice_completed; + bool_t pad[2]; } SalStreamDescription; -#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4 +const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc); +const char *sal_stream_description_get_proto_as_string(const SalStreamDescription *desc); + +#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 8 typedef struct SalMediaDescription{ int refcount; @@ -217,6 +223,7 @@ typedef struct SalMediaDescription{ char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; bool_t ice_lite; bool_t ice_completed; + bool_t pad[2]; } SalMediaDescription; typedef struct SalMessage{ @@ -691,6 +698,7 @@ 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 int sal_get_random(void); unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size); belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name); void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer); From 2c0e4947ccfc1ffa98eb88f21ee295cd13f0e5ec Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 2 Mar 2014 11:39:10 +0100 Subject: [PATCH 292/439] fix crash in linphonec, update oRTP --- console/commands.c | 2 -- oRTP | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/console/commands.c b/console/commands.c index ee876ebdb..725ce8e4b 100644 --- a/console/commands.c +++ b/console/commands.c @@ -617,8 +617,6 @@ lpc_cmd_chat(LinphoneCore *lc, char *args) } LinphoneChatRoom *cr = linphone_core_create_chat_room(lc,arg1); linphone_chat_room_send_message(cr,arg2); - linphone_chat_room_destroy(cr); - return 1; } diff --git a/oRTP b/oRTP index 7bac4a3ec..b2e5f313e 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 7bac4a3ecaa2e74e9e4fd3de2c2ddb57fe7945d6 +Subproject commit b2e5f313e6f245588751835ccd01bcd5dc2e8b1e From cac1551acddc8441d9d1701ad026d17eec9e6619 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 3 Mar 2014 10:53:55 +0100 Subject: [PATCH 293/439] Reworked lpconfig global default values section to have one default value for each section + use proxy default value when creating proxy config --- coreapi/linphonecore_jni.cc | 5 ++ coreapi/lpconfig.c | 34 ++++++++++++++ coreapi/lpconfig.h | 47 +++++++++++++------ coreapi/proxy.c | 39 +++++++++------ .../org/linphone/core/LinphoneCore.java | 6 +++ .../linphone/core/LinphoneCoreFactory.java | 5 +- .../org/linphone/core/LinphoneCoreImpl.java | 5 ++ 7 files changed, 111 insertions(+), 30 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index cbf3a1bd7..d19eacd51 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1417,6 +1417,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryptionMandat linphone_core_set_media_encryption_mandatory((LinphoneCore*)lc, yesno); } +extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createProxyConfig(JNIEnv* env, jobject thiz, jlong lc) { + LinphoneProxyConfig* proxy = linphone_core_create_proxy_config((LinphoneCore *)lc); + return (jlong) proxy; +} + //ProxyConfig extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) { diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index eaeaad71a..85bc80d8d 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -461,3 +461,37 @@ void lp_config_clean_section(LpConfig *lpconfig, const char *section){ int lp_config_needs_commit(const LpConfig *lpconfig){ return lpconfig->modified>0; } + +static const char *DEFAULT_VALUES_SUFFIX = "_default_values"; + +int lp_config_get_default_int(const LpConfig *lpconfig, const char *section, const char *key, int default_value) { + char default_section[MAX_LEN]; + strcpy(default_section, section); + strcat(default_section, DEFAULT_VALUES_SUFFIX); + + return lp_config_get_int(lpconfig, default_section, key, default_value); +} + +int64_t lp_config_get_default_int64(const LpConfig *lpconfig, const char *section, const char *key, int64_t default_value) { + char default_section[MAX_LEN]; + strcpy(default_section, section); + strcat(default_section, DEFAULT_VALUES_SUFFIX); + + return lp_config_get_int64(lpconfig, default_section, key, default_value); +} + +float lp_config_get_default_float(const LpConfig *lpconfig, const char *section, const char *key, float default_value) { + char default_section[MAX_LEN]; + strcpy(default_section, section); + strcat(default_section, DEFAULT_VALUES_SUFFIX); + + return lp_config_get_float(lpconfig, default_section, key, default_value); +} + +const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value) { + char default_section[MAX_LEN]; + strcpy(default_section, section); + strcat(default_section, DEFAULT_VALUES_SUFFIX); + + return lp_config_get_string(lpconfig, default_section, key, default_value); +} diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 3af570e79..d41556f6f 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -55,20 +55,6 @@ typedef struct _LpConfig LpConfig; extern "C" { #endif - -#define LP_CONFIG_DEFAULT_STRING(config, name, default) \ - (config) ? (lp_config_get_string(config, "default_values", name, default)) : (default) - -#define LP_CONFIG_DEFAULT_INT(config, name, default) \ - (config) ? (lp_config_get_int(config, "default_values", name, default)) : (default) - -#define LP_CONFIG_DEFAULT_INT64(config, name, default) \ - (config) ? (lp_config_get_int64(config, "default_values", name, default)) : (default) - -#define LP_CONFIG_DEFAULT_FLOAT(config, name, default) \ - (config) ? (lp_config_get_float(config, "default_values", name, default)) : (default) - - /** * Instantiates a LpConfig object from a user config file. * @@ -220,7 +206,40 @@ void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, voi /*tells whether uncommited (with lp_config_sync()) modifications exist*/ int lp_config_needs_commit(const LpConfig *lpconfig); + LINPHONE_PUBLIC void lp_config_destroy(LpConfig *cfg); + +/** + * Retrieves a default configuration item as an integer, given its section, key, and default value. + * + * @ingroup misc + * The default integer value is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC int lp_config_get_default_int(const LpConfig *lpconfig, const char *section, const char *key, int default_value); + +/** + * Retrieves a default configuration item as a 64 bit integer, given its section, key, and default value. + * + * @ingroup misc + * The default integer value is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC int64_t lp_config_get_default_int64(const LpConfig *lpconfig, const char *section, const char *key, int64_t default_value); + +/** + * Retrieves a default configuration item as a float, given its section, key, and default value. + * + * @ingroup misc + * The default float value is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC float lp_config_get_default_float(const LpConfig *lpconfig, const char *section, const char *key, float default_value); + +/** + * Retrieves a default configuration item as a string, given its section, key, and default value. + * + * @ingroup misc + * The default value string is returned if the config item isn't found. +**/ +LINPHONE_PUBLIC const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value); #ifdef __cplusplus } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 8d485b910..5633038f4 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -41,15 +41,25 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL)); } -static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj){ - const char *dial_prefix; - memset(obj,0,sizeof(LinphoneProxyConfig)); - obj->magic=linphone_proxy_config_magic; - obj->expires=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"reg_expires",3600); - dial_prefix=LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",NULL); - if (dial_prefix) obj->dial_prefix=ms_strdup(dial_prefix); - obj->dial_escape_plus=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"dial_escape_plus",0); - obj->privacy=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"privacy",LinphonePrivacyDefault); +static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *obj) { + const char *dial_prefix = lc ? lp_config_get_default_string(lc->config,"proxy","dial_prefix",NULL) : NULL; + const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL; + const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL; + const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL; + const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL; + const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL; + + memset(obj, 0, sizeof(LinphoneProxyConfig)); + obj->magic = linphone_proxy_config_magic; + obj->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600; + obj->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL; + obj->dial_escape_plus = lc ? lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0; + obj->privacy = lc ? lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault; + obj->reg_identity = identity ? ms_strdup(identity) : NULL; + obj->reg_proxy = proxy ? ms_strdup(proxy) : NULL; + obj->reg_route = route ? ms_strdup(route) : NULL; + obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL; + obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL; } /** @@ -64,6 +74,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj LinphoneProxyConfig *linphone_proxy_config_new() { return linphone_core_create_proxy_config(NULL); } + LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) { LinphoneProxyConfig *obj=NULL; obj=ms_new(LinphoneProxyConfig,1); @@ -71,8 +82,6 @@ LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) { return obj; } - - /** * Destroys a proxy config. * @@ -1091,19 +1100,19 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config linphone_proxy_config_set_contact_uri_parameters(cfg,lp_config_get_string(config,key,"contact_uri_parameters",NULL)); - linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",LP_CONFIG_DEFAULT_INT(config,"reg_expires",600))); + linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",lp_config_get_default_int(config,"proxy","reg_expires",600))); linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0)); linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0)); - linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",LP_CONFIG_DEFAULT_INT(config,"dial_escape_plus",0))); - linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",LP_CONFIG_DEFAULT_STRING(config,"dial_prefix",NULL))); + linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",lp_config_get_default_int(config,"proxy","dial_escape_plus",0))); + linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",lp_config_get_default_string(config,"proxy","dial_prefix",NULL))); tmp=lp_config_get_string(config,key,"type",NULL); if (tmp!=NULL && strlen(tmp)>0) linphone_proxy_config_set_sip_setup(cfg,tmp); - linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",LP_CONFIG_DEFAULT_INT(config,"privacy",LinphonePrivacyDefault))); + linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",lp_config_get_default_int(config,"proxy","privacy",LinphonePrivacyDefault))); return cfg; } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 03d946a4e..143ccf40a 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1518,4 +1518,10 @@ public interface LinphoneCore { * @return true if successful, false otherwise. */ public boolean acceptEarlyMediaWithParams(LinphoneCall call, LinphoneCallParams params); + + /** + * + * @return + */ + public LinphoneProxyConfig createProxyConfig(); } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index f394dbb4e..0a6efc305 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -87,7 +87,8 @@ abstract public class LinphoneCoreFactory { 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; + abstract public LinphoneProxyConfig createProxyConfig(String identity, String proxy,String route,boolean enableRegister) throws LinphoneCoreException; + /** * Enable verbose traces * @param enable @@ -96,12 +97,14 @@ abstract public class LinphoneCoreFactory { abstract public void setDebugMode(boolean enable, String tag); abstract public void setLogHandler(LinphoneLogHandler handler); + /** * Create a LinphoneFriend, similar to {@link #createLinphoneFriend()} + {@link LinphoneFriend#setAddress(LinphoneAddress)} * @param friendUri a buddy address, must be a sip uri like sip:joe@sip.linphone.org * @return a new LinphoneFriend with address initialized */ abstract public LinphoneFriend createLinphoneFriend(String friendUri); + /** * Create a new LinphoneFriend * @return diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 9b885a6b2..5e0ae7fce 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -145,6 +145,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setChatDatabasePath(long nativePtr, String path); private native long[] getChatRooms(long nativePtr); private native int migrateToMultiTransport(long nativePtr); + private native long createProxyConfig(long nativePtr); LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata) throws IOException { mListener = listener; @@ -1129,4 +1130,8 @@ class LinphoneCoreImpl implements LinphoneCore { long ptrParams = params != null ? ((LinphoneCallParamsImpl) params).nativePtr : 0; return acceptEarlyMediaWithParams(nativePtr, getCallPtr(call), ptrParams); } + @Override + public LinphoneProxyConfig createProxyConfig() { + return new LinphoneProxyConfigImpl(createProxyConfig(nativePtr)); + } } From 6f819de1775f74f283dc08b48570adb6ae420ead Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 3 Mar 2014 14:41:34 +0100 Subject: [PATCH 294/439] Preliminary work for tester compilation for iOS --- configure.ac | 7 ++- tester/Makefile.am | 20 ++++++--- tester/liblinphone_tester.c | 80 +++++++++++++++++++--------------- tester/liblinphone_tester.h | 1 + tester/liblinphonetester_ios.h | 24 ++++++++++ tester/liblinphonetester_ios.m | 52 ++++++++++++++++++++++ 6 files changed, 141 insertions(+), 43 deletions(-) create mode 100644 tester/liblinphonetester_ios.h create mode 100644 tester/liblinphonetester_ios.m diff --git a/configure.ac b/configure.ac index a8114f18b..4e586d32d 100644 --- a/configure.ac +++ b/configure.ac @@ -49,6 +49,8 @@ AM_PROG_CC_C_O AC_CHECK_PROGS(MD5SUM,[md5sum md5]) AM_CONDITIONAL(HAVE_MD5SUM,test -n $MD5SUM) +ios_found=no + case $target in *mingw32ce) CFLAGS="$CFLAGS -D_WIN32_WCE -DORTP_STATIC -D_WIN32_WINNT=0x0501" @@ -68,7 +70,9 @@ case $target in ;; armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin) CFLAGS="$CFLAGS -DTARGET_OS_IPHONE=1 " + LIBS="$LIBS -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation" ios_found=yes + AC_PROG_OBJC ;; x86_64-apple-darwin*|i686-apple-darwin*) MSPLUGINS_CFLAGS="" @@ -79,8 +83,7 @@ case $target in esac - - +AM_CONDITIONAL(BUILD_IOS, test x$ios_found = xyes) AC_SUBST(ACLOCAL_MACOS_FLAGS) AC_SUBST(CONSOLE_FLAGS) diff --git a/tester/Makefile.am b/tester/Makefile.am index 5c1f72239..b59c1e077 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -18,18 +18,24 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ remote_provisioning_tester.c -#liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) - -#liblinphone_tester_LDFLAGS=$(CUNIT_LIBS) - - AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) $(LIBXML2_LIBS) -AM_LDFLAGS=$(CUNIT_LIBS) +AM_LDFLAGS = $(CUNIT_LIBS) + +AM_CFLAGS = $(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) +AM_OBJCFLAGS = $(AM_CFLAGS) -DNO_XCODE + +liblinphone_tester_LDFLAGS= + +if BUILD_IOS +liblinphone_tester_SOURCES += liblinphonetester_ios.m liblinphonetester_ios.h +liblinphone_tester_LDFLAGS += -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation +# we have to force the linker to use c-style link when mixing Obj-C and C sources, otherwise the Obj-C linker is used, which gives strange errors (UTF8?) +liblinphone_tester_LINK = $(LINK) +endif -AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) test: liblinphone_tester ./liblinphone_tester --config $(abs_srcdir) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 2cb84fca0..0f55ea131 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -1,20 +1,20 @@ /* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. + This program is free software: you can 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. + This program is distributed in the hope that 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 . -*/ + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ #include #include "CUnit/Basic.h" @@ -35,6 +35,9 @@ static int nb_test_suites = 0; static unsigned char curses = 0; #endif +#if TARGET_OS_IPHONE +#include "liblinphonetester_ios.h" +#endif const char* test_domain="sipopen.example.org"; @@ -45,13 +48,11 @@ const char* test_route="sip2.linphone.org"; #if WINAPI_FAMILY_PHONE_APP const char *liblinphone_tester_file_prefix="Assets"; -#else -#ifdef __QNX__ +#elif defined(__QNX__) const char *liblinphone_tester_file_prefix="./app/native/assets/"; #else const char *liblinphone_tester_file_prefix="."; #endif -#endif const char *userhostsfile = "tester_hosts"; @@ -78,8 +79,8 @@ LinphoneAddress * create_linphone_address(const char * domain) { static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { stats* counters; ms_message("Auth info requested for user id [%s] at realm [%s]\n" - ,username - ,realm); + ,username + ,realm); counters = get_stats(lc); counters->number_of_auth_info_requested++; } @@ -146,9 +147,9 @@ bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { int retry=0; MSList* iterator; while ((counter==NULL || *counternext) { - linphone_core_iterate((LinphoneCore*)(iterator->data)); - } + for (iterator=lcs;iterator!=NULL;iterator=iterator->next) { + linphone_core_iterate((LinphoneCore*)(iterator->data)); + } ms_usleep(100000); } if(counter && *counternext) { - linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); + linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); } if((pt = linphone_core_find_payload_type(lc,type,rate,1))) { linphone_core_enable_payload_type(lc,pt, enable); @@ -202,7 +203,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->v_table.notify_received=linphone_notify_received; mgr->v_table.publish_state_changed=linphone_publish_state_changed; mgr->v_table.configuring_status=linphone_configuration_status; - + reset_counters(&mgr->stat); if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file); mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_path, mgr); @@ -413,12 +414,12 @@ 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) { 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; 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); } @@ -430,6 +431,7 @@ static void liblinphone_tester_qnx_log_handler(OrtpLogLevel lev, const char *fmt } #endif /* __QNX__ */ + void helper(const char *name) { fprintf(stderr,"%s \t--help\n" "\t\t\t--verbose\n" @@ -449,13 +451,21 @@ void helper(const char *name) { } #define CHECK_ARG(argument, index, argc) \ - if(index >= argc) { \ - fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ - return -1; \ - } \ +if(index >= argc) { \ +fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ +return -1; \ +} \ #ifndef WINAPI_FAMILY_PHONE_APP -int main (int argc, char *argv[]) { + + +#if TARGET_OS_IPHONE +int ios_tester_main(int argc, char * argv[]) +#else +int main (int argc, char *argv[]) +#endif + +{ int i,j; int ret; const char *suite_name=NULL; @@ -465,6 +475,8 @@ int main (int argc, char *argv[]) { linphone_core_set_log_handler(linphone_android_ortp_log_handler); #elif defined(__QNX__) linphone_core_set_log_handler(liblinphone_tester_qnx_log_handler); +#elif TARGET_OS_IPHONE + linphone_core_set_log_handler(liblinphone_tester_ios_log_handler); #else linphone_core_set_log_file(NULL); #endif diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index edf51e1fb..1f8640063 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -223,5 +223,6 @@ const char *liblinphone_tester_get_notify_content(void); void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee); + #endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/liblinphonetester_ios.h b/tester/liblinphonetester_ios.h new file mode 100644 index 000000000..a3b6177c3 --- /dev/null +++ b/tester/liblinphonetester_ios.h @@ -0,0 +1,24 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + + +#include "ortp/ortp.h" + +int apple_start_tests(int argc, char* argv[]); + +void liblinphone_tester_ios_log_handler(OrtpLogLevel level, const char* fmt, va_list args); \ No newline at end of file diff --git a/tester/liblinphonetester_ios.m b/tester/liblinphonetester_ios.m new file mode 100644 index 000000000..0d4e7e37f --- /dev/null +++ b/tester/liblinphonetester_ios.m @@ -0,0 +1,52 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "liblinphonetester_ios.h" + +#include +#import +#import + +extern int ios_tester_main(int argc, char * argv[]); + +int g_argc; +char** g_argv; + +static void* apple_main(void* data) { + ios_tester_main(g_argc,g_argv); + return NULL; +} + +int apple_start_tests(int argc, char* argv[]) +{ + pthread_t main_thread; + g_argc=argc; + g_argv=argv; + return (int)pthread_create(&main_thread,NULL,apple_main,NULL); +} + +void liblinphone_tester_ios_log_handler(OrtpLogLevel level, const char* fmt, va_list args) +{ + NSLogv([NSString stringWithUTF8String:fmt], args); +} + +#ifdef NO_XCODE /* when compiling under xcode the main is elsewhere */ +int main( int argc, char* argv[]){ + return ios_tester_main(argc, argv); +} +#endif \ No newline at end of file From 7d64dedf12c4a7795d2ffe204416543025055de2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 3 Mar 2014 15:07:11 +0100 Subject: [PATCH 295/439] Fixed missing init in proxy config creation + added test for proxy_default_values in lpconfig --- coreapi/proxy.c | 1 + tester/rcfiles/marie_remote_default_values_rc | 2 ++ tester/remote_provisioning_tester.c | 14 +++++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tester/rcfiles/marie_remote_default_values_rc diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 5633038f4..635d94ec5 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -52,6 +52,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob memset(obj, 0, sizeof(LinphoneProxyConfig)); obj->magic = linphone_proxy_config_magic; obj->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600; + obj->reg_sendregister = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 0) : 0; obj->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL; obj->dial_escape_plus = lc ? lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0; obj->privacy = lc ? lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault; diff --git a/tester/rcfiles/marie_remote_default_values_rc b/tester/rcfiles/marie_remote_default_values_rc new file mode 100644 index 000000000..ec5e4f633 --- /dev/null +++ b/tester/rcfiles/marie_remote_default_values_rc @@ -0,0 +1,2 @@ +[misc] +config-uri=http://smtp.linphone.org/marie_default diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 15e2ff05e..850542355 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -76,13 +76,25 @@ static void remote_provisioning_invalid(void) { linphone_core_manager_destroy(marie); } +static void remote_provisioning_default_values(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_default_values_rc", FALSE); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + LinphoneProxyConfig *lpc = linphone_core_create_proxy_config(marie->lc); + CU_ASSERT_TRUE(lpc->reg_sendregister == 1); + CU_ASSERT_TRUE(lpc->expires == 604800); + CU_ASSERT_TRUE(strcmp(lpc->reg_proxy, "") == 0); + CU_ASSERT_TRUE(strcmp(lpc->reg_identity, "sip:?@sip.linphone.org") == 0); + linphone_core_manager_destroy(marie); +} + test_t remote_provisioning_tests[] = { { "Remote provisioning skipped", remote_provisioning_skipped }, { "Remote provisioning successful behind http", remote_provisioning_http }, { "Remote provisioning successful behind https", remote_provisioning_https }, { "Remote provisioning 404 not found", remote_provisioning_not_found }, { "Remote provisioning invalid", remote_provisioning_invalid }, - { "Remote provisioning transient successful", remote_provisioning_transient } + { "Remote provisioning transient successful", remote_provisioning_transient }, + { "Remote provisioning default values", remote_provisioning_default_values } }; test_suite_t remote_provisioning_test_suite = { From 4e9d8a1e9707ecbaf3768d39bb9c953e25d282a4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 3 Mar 2014 17:28:19 +0100 Subject: [PATCH 296/439] Improved default values test --- tester/remote_provisioning_tester.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 850542355..f38ab9a67 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -77,12 +77,14 @@ static void remote_provisioning_invalid(void) { } static void remote_provisioning_default_values(void) { + LinphoneProxyConfig *lpc; LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_default_values_rc", FALSE); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); - LinphoneProxyConfig *lpc = linphone_core_create_proxy_config(marie->lc); - CU_ASSERT_TRUE(lpc->reg_sendregister == 1); + lpc = linphone_core_create_proxy_config(marie->lc); + CU_ASSERT_TRUE(lpc->reg_sendregister == TRUE); CU_ASSERT_TRUE(lpc->expires == 604800); CU_ASSERT_TRUE(strcmp(lpc->reg_proxy, "") == 0); + CU_ASSERT_TRUE(strcmp(lpc->reg_route, "") == 0); CU_ASSERT_TRUE(strcmp(lpc->reg_identity, "sip:?@sip.linphone.org") == 0); linphone_core_manager_destroy(marie); } From 4a814588b5e67a27ca2347caafa2531049c6b4f5 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 4 Mar 2014 09:22:20 +0100 Subject: [PATCH 297/439] Fix compilation with Visual Studio. --- coreapi/xml2lpc.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/coreapi/xml2lpc.c b/coreapi/xml2lpc.c index d02133674..bacc7d4ba 100644 --- a/coreapi/xml2lpc.c +++ b/coreapi/xml2lpc.c @@ -221,21 +221,27 @@ static int processDoc(xmlNode *node, xml2lpc_context *ctx) { } static int internal_convert_xml2lpc(xml2lpc_context *ctx) { + xmlNode *rootNode; + int ret; + xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started"); - xmlNode *rootNode = xmlDocGetRootElement(ctx->doc); + rootNode = xmlDocGetRootElement(ctx->doc); //dumpNodes(0, rootNode, cbf, ctx); - int ret = processDoc(rootNode, ctx); + ret = processDoc(rootNode, ctx); xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse ended ret:%d", ret); return ret; } int xml2lpc_validate(xml2lpc_context *xmlCtx) { - xml2lpc_context_clear_logs(xmlCtx); xmlSchemaValidCtxtPtr validCtx; - xmlSchemaParserCtxtPtr parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd); + xmlSchemaParserCtxtPtr parserCtx; + int ret; + + xml2lpc_context_clear_logs(xmlCtx); + parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd); validCtx = xmlSchemaNewValidCtxt(xmlSchemaParse(parserCtx)); xmlSchemaSetValidErrors(validCtx, xml2lpc_genericxml_error, xml2lpc_genericxml_warning, xmlCtx); - int ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc); + ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc); if(ret > 0) { if(strlen(xmlCtx->warningBuffer) > 0) xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer); From f8f17140ca0ea753bae642b3d856fb6833ae9ed1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 4 Mar 2014 09:22:43 +0100 Subject: [PATCH 298/439] Fix compilation with CMake. --- CMakeLists.txt | 1 - coreapi/CMakeLists.txt | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d34e4890..ae3952338 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,6 @@ include_directories( include/ coreapi/ ${CMAKE_CURRENT_BINARY_DIR}/coreapi/ - ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/libxml2/ ) include_directories( diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 2fa09d9ae..8b2650950 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -74,11 +74,13 @@ set(SOURCE_FILES offeranswer.c presence.c proxy.c + remote_provisioning.c sal.c siplogin.c sipsetup.c #TunnelManager.cc xml.c + xml2lpc.c bellesip_sal/sal_impl.h enum.h event.h @@ -90,6 +92,7 @@ set(SOURCE_FILES offeranswer.h private.h sipsetup.h + xml2lpc.h ) add_definitions( From 244b028f4557c5887f364c1976dbac13e09e1305 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 4 Mar 2014 09:46:38 +0100 Subject: [PATCH 299/439] Place AC_PROG_OBJC in non-conditional statement --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4e586d32d..17f4dab25 100644 --- a/configure.ac +++ b/configure.ac @@ -39,6 +39,7 @@ AC_CONFIG_MACRO_DIR([m4]) dnl don't put anythingelse before AC_PROG_CC unless checking if macro still work for clang AC_PROG_CXX(["xcrun clang++" g++]) AC_PROG_CC(["xcrun clang" gcc]) +AC_PROG_OBJC gl_LD_OUTPUT_DEF @@ -72,7 +73,6 @@ case $target in CFLAGS="$CFLAGS -DTARGET_OS_IPHONE=1 " LIBS="$LIBS -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation" ios_found=yes - AC_PROG_OBJC ;; x86_64-apple-darwin*|i686-apple-darwin*) MSPLUGINS_CFLAGS="" From b85a51105a0bd174a5c506afb11d6661117f36e0 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 4 Mar 2014 12:27:57 +0100 Subject: [PATCH 300/439] Split the tester in two components: liblinphonetester.la and the executable liblinphone_tester . This will ease iOS usage (and probably others). --- configure.ac | 2 +- tester/Makefile.am | 42 ++++++++++++++++++++++--------------- tester/liblinphone_tester.h | 10 ++++----- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index 17f4dab25..7f98c26a6 100644 --- a/configure.ac +++ b/configure.ac @@ -39,7 +39,7 @@ AC_CONFIG_MACRO_DIR([m4]) dnl don't put anythingelse before AC_PROG_CC unless checking if macro still work for clang AC_PROG_CXX(["xcrun clang++" g++]) AC_PROG_CC(["xcrun clang" gcc]) -AC_PROG_OBJC +AC_PROG_OBJC(["xcrun clang" gcc]) gl_LD_OUTPUT_DEF diff --git a/tester/Makefile.am b/tester/Makefile.am index b59c1e077..92023f78c 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -3,9 +3,14 @@ EXTRA_DIST= tester_hosts sounds images certificates rcfiles if BUILD_CUNIT_TESTS -noinst_PROGRAMS=liblinphone_tester +# there are 2 targets: liblinphonetester.la and the executable liblinphone_tester -liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ +liblinphonedir = $(includedir)/linphone +liblinphone_HEADERS = liblinphone_tester.h + +lib_LTLIBRARIES = liblinphonetester.la + +liblinphonetester_la_SOURCES = \ setup_tester.c \ register_tester.c \ message_tester.c \ @@ -18,31 +23,34 @@ liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ remote_provisioning_tester.c -AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/coreapi +AM_CFLAGS = $(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) +AM_OBJCFLAGS = $(AM_CFLAGS) -LDADD=$(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) $(LIBXML2_LIBS) - -AM_LDFLAGS = $(CUNIT_LIBS) - -AM_CFLAGS = $(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) -AM_OBJCFLAGS = $(AM_CFLAGS) -DNO_XCODE - -liblinphone_tester_LDFLAGS= if BUILD_IOS -liblinphone_tester_SOURCES += liblinphonetester_ios.m liblinphonetester_ios.h -liblinphone_tester_LDFLAGS += -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation -# we have to force the linker to use c-style link when mixing Obj-C and C sources, otherwise the Obj-C linker is used, which gives strange errors (UTF8?) -liblinphone_tester_LINK = $(LINK) + +#we build the liblinphonetester as a library, not as an executable, so that it is usable in XCode +liblinphonetester_la_SOURCES += liblinphonetester_ios.m liblinphonetester_ios.h +liblinphonetester_la_LDFLAGS = -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation $(CUNIT_LIBS) + +else + +noinst_PROGRAMS = liblinphone_tester + +liblinphone_tester_LDFLAGS = $(CUNIT_LIBS) +liblinphone_tester_SOURCES = liblinphone_tester.c +liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) $(LIBXML2_LIBS) liblinphonetester.la + endif test: liblinphone_tester ./liblinphone_tester --config $(abs_srcdir) -else +else !BUILD_CUNIT_TESTS test: @echo "CUnit must be installed to be able to run the tests!" -endif +endif !BUILD_CUNIT_TESTS diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 1f8640063..36ff30de2 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -71,11 +71,11 @@ extern int liblinphone_tester_run_tests(const char *suite_name, const char *test #endif -const char* test_domain; -const char* auth_domain; -const char* test_username; -const char* test_password; -const char* test_route; +extern const char* test_domain; +extern const char* auth_domain; +extern const char* test_username; +extern const char* test_password; +extern const char* test_route; typedef struct _stats { From 7e00357fd082491f5929f3e8f4b45cfce8805273 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 4 Mar 2014 14:32:05 +0100 Subject: [PATCH 301/439] Fix compilation with belle-sip 1.3.1. --- configure.ac | 2 +- coreapi/bellesip_sal/sal_sdp.c | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 7f98c26a6..20148b3f6 100644 --- a/configure.ac +++ b/configure.ac @@ -753,7 +753,7 @@ if test x$enable_msg_storage != xfalse; then fi -PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.3.0]) +PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.3.1]) SIPSTACK_CFLAGS="$BELLESIP_CFLAGS" SIPSTACK_LIBS="$BELLESIP_LIBS" diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 1f0da7fb0..32a74a6ee 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -259,7 +259,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S 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_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 ) ); @@ -278,6 +278,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { belle_sip_list_t *attribute_it; const belle_sdp_attribute_t *attribute; + const belle_sdp_raw_attribute_t *raw_attribute; char tmp[256], tmp2[256]; int valid_count = 0; int nb; @@ -287,9 +288,10 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med ; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; attribute_it=attribute_it->next ) { attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data ); + raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute); - 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", + if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_raw_attribute_get_value ( raw_attribute ) !=NULL ) { + nb = sscanf ( belle_sdp_raw_attribute_get_value ( raw_attribute ), "%d %256s inline:%256s", &stream->crypto[valid_count].tag, tmp, tmp2 ); @@ -316,7 +318,7 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med 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_raw_attribute_get_value ( raw_attribute ),nb ); } } } @@ -326,14 +328,16 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { belle_sip_list_t *attribute_it; const belle_sdp_attribute_t *attribute; + const belle_sdp_raw_attribute_t *raw_attribute; const char *att_name; const char *value; int nb_ice_candidates = 0; for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { - attribute=(belle_sdp_attribute_t*)attribute_it->data; + attribute=BELLE_SDP_ATTRIBUTE(attribute_it->data); + raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute); att_name = belle_sdp_attribute_get_name(attribute); - value = belle_sdp_attribute_get_value(attribute); + value = belle_sdp_raw_attribute_get_value(raw_attribute); if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; @@ -374,6 +378,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, belle_sdp_connection_t* cnx; belle_sdp_media_t* media; const belle_sdp_attribute_t* attribute; + const belle_sdp_raw_attribute_t* raw_attribute; const char* value; const char *mtype,*proto; @@ -435,7 +440,8 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, 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){ + raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute); + if (attribute && (value=belle_sdp_raw_attribute_get_value(raw_attribute))!=NULL){ char tmp[256]; int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp); if (nb == 1) { From e112161ec31d828ae1603a8c5da2b200cc56c682 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 4 Mar 2014 15:26:13 +0100 Subject: [PATCH 302/439] Separater main() from lib functions in the tester --- tester/Makefile.am | 9 +- tester/liblinphone_tester.c | 472 ++++----------------------------- tester/liblinphone_tester.h | 2 + tester/liblinphonetester_ios.m | 6 - tester/tester.c | 382 ++++++++++++++++++++++++++ 5 files changed, 440 insertions(+), 431 deletions(-) create mode 100644 tester/tester.c diff --git a/tester/Makefile.am b/tester/Makefile.am index 92023f78c..95beaf139 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -10,7 +10,7 @@ liblinphone_HEADERS = liblinphone_tester.h lib_LTLIBRARIES = liblinphonetester.la -liblinphonetester_la_SOURCES = \ +liblinphonetester_la_SOURCES = tester.c \ setup_tester.c \ register_tester.c \ message_tester.c \ @@ -25,14 +25,13 @@ liblinphonetester_la_SOURCES = \ AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/coreapi AM_CFLAGS = $(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) -AM_OBJCFLAGS = $(AM_CFLAGS) - if BUILD_IOS #we build the liblinphonetester as a library, not as an executable, so that it is usable in XCode -liblinphonetester_la_SOURCES += liblinphonetester_ios.m liblinphonetester_ios.h -liblinphonetester_la_LDFLAGS = -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation $(CUNIT_LIBS) +liblinphonetester_la_OBJCFLAGS = $(AM_CFLAGS) +liblinphonetester_la_SOURCES += liblinphonetester_ios.m liblinphonetester_ios.h +liblinphonetester_la_LDFLAGS = -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation $(CUNIT_LIBS) else diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 0f55ea131..f47a556b9 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -25,370 +25,18 @@ #include "CUnit/CUCurses.h" #endif -static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data); - -static test_suite_t **test_suite = NULL; -static int nb_test_suites = 0; - - -#if HAVE_CU_CURSES -static unsigned char curses = 0; -#endif - -#if TARGET_OS_IPHONE -#include "liblinphonetester_ios.h" -#endif - - -const char* test_domain="sipopen.example.org"; -const char* auth_domain="sip.example.org"; -const char* test_username="liblinphone_tester"; -const char* test_password="secret"; -const char* test_route="sip2.linphone.org"; - -#if WINAPI_FAMILY_PHONE_APP -const char *liblinphone_tester_file_prefix="Assets"; -#elif defined(__QNX__) -const char *liblinphone_tester_file_prefix="./app/native/assets/"; -#else -const char *liblinphone_tester_file_prefix="."; -#endif - -const char *userhostsfile = "tester_hosts"; - #ifdef ANDROID + extern void AndroidPrintf(FILE *stream, const char *fmt, ...); #define fprintf(file, fmt, ...) AndroidPrintf(file, fmt, ##__VA_ARGS__) -#endif - -LinphoneAddress * create_linphone_address(const char * domain) { - LinphoneAddress *addr = linphone_address_new(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(addr); - linphone_address_set_username(addr,test_username); - CU_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr)); - if (!domain) domain= test_route; - linphone_address_set_domain(addr,domain); - CU_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr)); - linphone_address_set_display_name(addr, NULL); - linphone_address_set_display_name(addr, "Mr Tester"); - CU_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); - return addr; -} - -static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { - stats* counters; - ms_message("Auth info requested for user id [%s] at realm [%s]\n" - ,username - ,realm); - counters = get_stats(lc); - counters->number_of_auth_info_requested++; -} - - - -void reset_counters( stats* counters) { - memset(counters,0,sizeof(stats)); -} - -static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) { - LinphoneCore* lc; - char filepath[256]={0}; - char ringpath[256]={0}; - char ringbackpath[256]={0}; - char rootcapath[256]={0}; - char dnsuserhostspath[256]={0}; - char nowebcampath[256]={0}; - - if (path==NULL) path="."; - - if (file){ - sprintf(filepath, "%s/%s", path, file); - CU_ASSERT_TRUE_FATAL(ortp_file_exist(filepath)==0); - } - - lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL, user_data); - - sal_enable_test_features(lc->sal,TRUE); - snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cafile.pem", path); - linphone_core_set_root_ca(lc,rootcapath); - - sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); - sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); - - snprintf(ringpath,sizeof(ringpath), "%s/sounds/oldphone.wav",path); - snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/ringback.wav", path); - linphone_core_set_ring(lc, ringpath); - linphone_core_set_ringback(lc, ringbackpath); - - snprintf(nowebcampath, sizeof(nowebcampath), "%s/images/nowebcamCIF.jpg", path); - linphone_core_set_static_picture(lc,nowebcampath); - return lc; -} - - -bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout) { - MSList* lcs=NULL; - bool_t result; - if (lc_1) - lcs=ms_list_append(lcs,lc_1); - if (lc_2) - lcs=ms_list_append(lcs,lc_2); - result=wait_for_list(lcs,counter,value,timout); - ms_list_free(lcs); - return result; -} - -bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { - return wait_for_until(lc_1, lc_2,counter,value,3000); -} - -bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { - int retry=0; - MSList* iterator; - while ((counter==NULL || *counternext) { - linphone_core_iterate((LinphoneCore*)(iterator->data)); - } - ms_usleep(100000); - } - if(counter && *counternext) { - linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); - } - if((pt = linphone_core_find_payload_type(lc,type,rate,1))) { - linphone_core_enable_payload_type(lc,pt, enable); - } - ms_list_free(codecs); -} - -static void enable_codec(LinphoneCore* lc,const char* type,int rate) { - set_codec_enable(lc,type,rate,TRUE); -} -stats * get_stats(LinphoneCore *lc){ - LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc); - return &manager->stat; -} - -LinphoneCoreManager *get_manager(LinphoneCore *lc){ - LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc); - return manager; -} - -LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies) { - LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); - LinphoneProxyConfig* proxy; - char *rc_path = NULL; - int proxy_count; - int retry=0; - - mgr->v_table.registration_state_changed=registration_state_changed; - mgr->v_table.auth_info_requested=auth_info_requested; - mgr->v_table.call_state_changed=call_state_changed; - mgr->v_table.text_received=text_message_received; - mgr->v_table.message_received=message_received; - mgr->v_table.is_composing_received=is_composing_received; - mgr->v_table.new_subscription_requested=new_subscription_requested; - mgr->v_table.notify_presence_received=notify_presence_received; - mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; - mgr->v_table.info_received=info_message_received; - mgr->v_table.subscription_state_changed=linphone_subscription_state_change; - mgr->v_table.notify_received=linphone_notify_received; - mgr->v_table.publish_state_changed=linphone_publish_state_changed; - mgr->v_table.configuring_status=linphone_configuration_status; - - reset_counters(&mgr->stat); - if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file); - mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_path, mgr); - /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ - if (check_for_proxies && rc_file) /**/ - proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)); - else - proxy_count=0; - - while (mgr->stat.number_of_LinphoneRegistrationOk2?(proxy_count-2)*10:0))) { - linphone_core_iterate(mgr->lc); - ms_usleep(100000); - } - CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count); - enable_codec(mgr->lc,"PCMU",8000); - - linphone_core_get_default_proxy(mgr->lc,&proxy); - if (proxy) { - mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); - linphone_address_clean(mgr->identity); - } - if (rc_path) ms_free(rc_path); - return mgr; -} - -LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) { - return linphone_core_manager_new2(rc_file, TRUE); -} - -void linphone_core_manager_stop(LinphoneCoreManager *mgr){ - if (mgr->lc) { - linphone_core_destroy(mgr->lc); - mgr->lc=NULL; - } -} - -void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { - if (mgr->lc) linphone_core_destroy(mgr->lc); - if (mgr->identity) linphone_address_destroy(mgr->identity); - ms_free(mgr); -} - - -static void add_test_suite(test_suite_t *suite) { - if (test_suite == NULL) { - test_suite = (test_suite_t **)malloc(10 * sizeof(test_suite_t *)); - } - test_suite[nb_test_suites] = suite; - nb_test_suites++; - if ((nb_test_suites % 10) == 0) { - test_suite = (test_suite_t **)realloc(test_suite, (nb_test_suites + 10) * sizeof(test_suite_t *)); - } -} - -static int run_test_suite(test_suite_t *suite) { - int i; - - CU_pSuite pSuite = CU_add_suite(suite->name, suite->init_func, suite->cleanup_func); - - for (i = 0; i < suite->nb_tests; i++) { - if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) { - return CU_get_error(); - } - } - - return 0; -} - -static int test_suite_index(const char *suite_name) { - int i; - - for (i = 0; i < liblinphone_tester_nb_test_suites(); i++) { - if ((strcmp(suite_name, test_suite[i]->name) == 0) && (strlen(suite_name) == strlen(test_suite[i]->name))) { - return i; - } - } - - return -1; -} - -static int test_index(const char *suite_name, const char *test_name) { - int j,i; - - j = test_suite_index(suite_name); - if(j != -1) { - for (i = 0; i < test_suite[j]->nb_tests; i++) { - if ((strcmp(test_name, test_suite[j]->tests[i].name) == 0) && (strlen(test_name) == strlen(test_suite[j]->tests[i].name))) { - return i; - } - } - } - - return -1; -} - -int liblinphone_tester_nb_test_suites(void) { - return nb_test_suites; -} - -int liblinphone_tester_nb_tests(const char *suite_name) { - int i = test_suite_index(suite_name); - if (i < 0) return 0; - return test_suite[i]->nb_tests; -} - -const char * liblinphone_tester_test_suite_name(int suite_index) { - if (suite_index >= liblinphone_tester_nb_test_suites()) return NULL; - return test_suite[suite_index]->name; -} - -const char * liblinphone_tester_test_name(const char *suite_name, int test_index) { - int suite_index = test_suite_index(suite_name); - if ((suite_index < 0) || (suite_index >= liblinphone_tester_nb_test_suites())) return NULL; - if (test_index >= test_suite[suite_index]->nb_tests) return NULL; - return test_suite[suite_index]->tests[test_index].name; -} - -void liblinphone_tester_init(void) { - add_test_suite(&setup_test_suite); - add_test_suite(®ister_test_suite); - add_test_suite(&call_test_suite); - add_test_suite(&message_test_suite); - add_test_suite(&presence_test_suite); -#ifdef UPNP - add_test_suite(&upnp_test_suite); -#endif - add_test_suite(&stun_test_suite); - add_test_suite(&event_test_suite); - add_test_suite(&flexisip_test_suite); - add_test_suite(&remote_provisioning_test_suite); -} - -void liblinphone_tester_uninit(void) { - if (test_suite != NULL) { - free(test_suite); - test_suite = NULL; - nb_test_suites = 0; - } -} - -int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) { - int i; - int ret; - /* initialize the CUnit test registry */ - if (CUE_SUCCESS != CU_initialize_registry()) - return CU_get_error(); - - for (i = 0; i < liblinphone_tester_nb_test_suites(); i++) { - run_test_suite(test_suite[i]); - } - - if (suite_name){ - CU_pSuite suite; - CU_basic_set_mode(CU_BRM_VERBOSE); - suite=CU_get_suite_by_name(suite_name, CU_get_registry()); - if (test_name) { - CU_pTest test=CU_get_test_by_name(test_name, suite); - CU_ErrorCode err= CU_basic_run_test(suite, test); - if (err != CUE_SUCCESS) ms_error("CU_basic_run_test error %d", err); - } else - CU_basic_run_suite(suite); - } else - { -#if HAVE_CU_CURSES - if (curses) { - /* Run tests using the CUnit curses interface */ - CU_curses_run_tests(); - } - else -#endif - { - /* Run all tests using the CUnit Basic interface */ - CU_basic_set_mode(CU_BRM_VERBOSE); - CU_basic_run_tests(); - } - } - - ret=CU_get_number_of_tests_failed()!=0; - CU_cleanup_registry(); - return ret; -} - -#ifdef ANDROID #include +#include +#include +#define CALLBACK_BUFFER_SIZE 1024 +static JNIEnv *current_env = NULL; +static jobject current_obj = 0; static const char* LogDomain = "liblinphone_tester"; void linphone_android_log_handler(int prio, const char *fmt, va_list args) { @@ -419,11 +67,49 @@ static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, 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; + default: prio = ANDROID_LOG_DEFAULT; break; } linphone_android_log_handler(prio, fmt, args); } -#endif + +void cunit_android_trace_handler(int level, const char *fmt, va_list args) { + char buffer[CALLBACK_BUFFER_SIZE]; + JNIEnv *env = current_env; + if(env == NULL) return; + vsnprintf(buffer, CALLBACK_BUFFER_SIZE, fmt, args); + jstring javaString = (*env)->NewStringUTF(env, buffer); + jint javaLevel = level; + jclass cls = (*env)->GetObjectClass(env, current_obj); + jmethodID method = (*env)->GetMethodID(env, cls, "printLog", "(ILjava/lang/String;)V"); + (*env)->CallVoidMethod(env, current_obj, method, javaLevel, javaString); + (*env)->DeleteLocalRef(env,javaString); +} + +JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject obj, jobjectArray stringArray) { + int i, ret; + int argc = (*env)->GetArrayLength(env, stringArray); + char **argv = (char**) malloc(sizeof(char*) * argc); + + for (i=0; iGetObjectArrayElement(env, stringArray, i); + const char *rawString = (const char *) (*env)->GetStringUTFChars(env, string, 0); + argv[i] = strdup(rawString); + (*env)->ReleaseStringUTFChars(env, string, rawString); + } + current_env = env; + current_obj = obj; + CU_set_trace_handler(cunit_android_trace_handler); + ret = main(argc, argv); + current_env = NULL; + CU_set_trace_handler(NULL); + for (i=0; i= argc) { \ +#define CHECK_ARG(argument, index, argc) \ +if(index >= argc) { \ fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ return -1; \ -} \ +} \ #ifndef WINAPI_FAMILY_PHONE_APP -#if TARGET_OS_IPHONE -int ios_tester_main(int argc, char * argv[]) -#else int main (int argc, char *argv[]) -#endif - { int i,j; int ret; @@ -475,8 +156,6 @@ int main (int argc, char *argv[]) linphone_core_set_log_handler(linphone_android_ortp_log_handler); #elif defined(__QNX__) linphone_core_set_log_handler(liblinphone_tester_qnx_log_handler); -#elif TARGET_OS_IPHONE - linphone_core_set_log_handler(liblinphone_tester_ios_log_handler); #else linphone_core_set_log_file(NULL); #endif @@ -531,12 +210,12 @@ int main (int argc, char *argv[]) // Check arguments if(suite_name != NULL) { - if(test_suite_index(suite_name) == -1) { + if(liblinphone_tester_test_suite_index(suite_name) == -1) { fprintf(stderr, "Suite \"%s\" not found\n", suite_name); return -1; } if(test_name != NULL) { - if(test_index(suite_name, test_name) == -1) { + if(liblinphone_tester_test_index(suite_name, test_name) == -1) { fprintf(stderr, "Test \"%s\" not found\n", test_name); return -1; } @@ -547,52 +226,5 @@ int main (int argc, char *argv[]) liblinphone_tester_uninit(); return ret; } -#endif - -#ifdef ANDROID -#include -#include -#define CALLBACK_BUFFER_SIZE 1024 -static JNIEnv *current_env = NULL; -static jobject current_obj = 0; - -void cunit_android_trace_handler(int level, const char *fmt, va_list args) { - char buffer[CALLBACK_BUFFER_SIZE]; - JNIEnv *env = current_env; - if(env == NULL) return; - vsnprintf(buffer, CALLBACK_BUFFER_SIZE, fmt, args); - jstring javaString = (*env)->NewStringUTF(env, buffer); - jint javaLevel = level; - jclass cls = (*env)->GetObjectClass(env, current_obj); - jmethodID method = (*env)->GetMethodID(env, cls, "printLog", "(ILjava/lang/String;)V"); - (*env)->CallVoidMethod(env, current_obj, method, javaLevel, javaString); - (*env)->DeleteLocalRef(env,javaString); -} - -JNIEXPORT - -JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject obj, jobjectArray stringArray) { - int i, ret; - int argc = (*env)->GetArrayLength(env, stringArray); - char **argv = (char**) malloc(sizeof(char*) * argc); - - for (i=0; iGetObjectArrayElement(env, stringArray, i); - const char *rawString = (const char *) (*env)->GetStringUTFChars(env, string, 0); - argv[i] = strdup(rawString); - (*env)->ReleaseStringUTFChars(env, string, rawString); - } - current_env = env; - current_obj = obj; - CU_set_trace_handler(cunit_android_trace_handler); - ret = main(argc, argv); - current_env = NULL; - CU_set_trace_handler(NULL); - for (i=0; i. + */ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" +#if HAVE_CU_CURSES +#include "CUnit/CUCurses.h" +#endif + +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data); + +static test_suite_t **test_suite = NULL; +static int nb_test_suites = 0; + + +#if HAVE_CU_CURSES +static unsigned char curses = 0; +#endif + +#if TARGET_OS_IPHONE +#include "liblinphonetester_ios.h" +#endif + + +const char* test_domain="sipopen.example.org"; +const char* auth_domain="sip.example.org"; +const char* test_username="liblinphone_tester"; +const char* test_password="secret"; +const char* test_route="sip2.linphone.org"; + +#if WINAPI_FAMILY_PHONE_APP +const char *liblinphone_tester_file_prefix="Assets"; +#elif defined(__QNX__) +const char *liblinphone_tester_file_prefix="./app/native/assets/"; +#else +const char *liblinphone_tester_file_prefix="."; +#endif + +const char *userhostsfile = "tester_hosts"; + +LinphoneAddress * create_linphone_address(const char * domain) { + LinphoneAddress *addr = linphone_address_new(NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(addr); + linphone_address_set_username(addr,test_username); + CU_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr)); + if (!domain) domain= test_route; + linphone_address_set_domain(addr,domain); + CU_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr)); + linphone_address_set_display_name(addr, NULL); + linphone_address_set_display_name(addr, "Mr Tester"); + CU_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); + return addr; +} + +static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { + stats* counters; + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + counters = get_stats(lc); + counters->number_of_auth_info_requested++; +} + + + +void reset_counters( stats* counters) { + memset(counters,0,sizeof(stats)); +} + +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data) { + LinphoneCore* lc; + char filepath[256]={0}; + char ringpath[256]={0}; + char ringbackpath[256]={0}; + char rootcapath[256]={0}; + char dnsuserhostspath[256]={0}; + char nowebcampath[256]={0}; + + if (path==NULL) path="."; + + if (file){ + sprintf(filepath, "%s/%s", path, file); + CU_ASSERT_TRUE_FATAL(ortp_file_exist(filepath)==0); + } + + lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL, user_data); + + sal_enable_test_features(lc->sal,TRUE); + snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cafile.pem", path); + linphone_core_set_root_ca(lc,rootcapath); + + sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); + sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); + + snprintf(ringpath,sizeof(ringpath), "%s/sounds/oldphone.wav",path); + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/ringback.wav", path); + linphone_core_set_ring(lc, ringpath); + linphone_core_set_ringback(lc, ringbackpath); + + snprintf(nowebcampath, sizeof(nowebcampath), "%s/images/nowebcamCIF.jpg", path); + linphone_core_set_static_picture(lc,nowebcampath); + return lc; +} + + +bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout) { + MSList* lcs=NULL; + bool_t result; + if (lc_1) + lcs=ms_list_append(lcs,lc_1); + if (lc_2) + lcs=ms_list_append(lcs,lc_2); + result=wait_for_list(lcs,counter,value,timout); + ms_list_free(lcs); + return result; +} + +bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { + return wait_for_until(lc_1, lc_2,counter,value,3000); +} + +bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { + int retry=0; + MSList* iterator; + while ((counter==NULL || *counternext) { + linphone_core_iterate((LinphoneCore*)(iterator->data)); + } + ms_usleep(100000); + } + if(counter && *counternext) { + linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); + } + if((pt = linphone_core_find_payload_type(lc,type,rate,1))) { + linphone_core_enable_payload_type(lc,pt, enable); + } + ms_list_free(codecs); +} + +static void enable_codec(LinphoneCore* lc,const char* type,int rate) { + set_codec_enable(lc,type,rate,TRUE); +} +stats * get_stats(LinphoneCore *lc){ + LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc); + return &manager->stat; +} + +LinphoneCoreManager *get_manager(LinphoneCore *lc){ + LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc); + return manager; +} + +LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies) { + LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); + LinphoneProxyConfig* proxy; + char *rc_path = NULL; + int proxy_count; + int retry=0; + + mgr->v_table.registration_state_changed=registration_state_changed; + mgr->v_table.auth_info_requested=auth_info_requested; + mgr->v_table.call_state_changed=call_state_changed; + mgr->v_table.text_received=text_message_received; + mgr->v_table.message_received=message_received; + mgr->v_table.is_composing_received=is_composing_received; + mgr->v_table.new_subscription_requested=new_subscription_requested; + mgr->v_table.notify_presence_received=notify_presence_received; + mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; + mgr->v_table.info_received=info_message_received; + mgr->v_table.subscription_state_changed=linphone_subscription_state_change; + mgr->v_table.notify_received=linphone_notify_received; + mgr->v_table.publish_state_changed=linphone_publish_state_changed; + mgr->v_table.configuring_status=linphone_configuration_status; + + reset_counters(&mgr->stat); + if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file); + mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_path, mgr); + /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ + if (check_for_proxies && rc_file) /**/ + proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)); + else + proxy_count=0; + + while (mgr->stat.number_of_LinphoneRegistrationOk2?(proxy_count-2)*10:0))) { + linphone_core_iterate(mgr->lc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count); + enable_codec(mgr->lc,"PCMU",8000); + + linphone_core_get_default_proxy(mgr->lc,&proxy); + if (proxy) { + mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + linphone_address_clean(mgr->identity); + } + if (rc_path) ms_free(rc_path); + return mgr; +} + +LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) { + return linphone_core_manager_new2(rc_file, TRUE); +} + +void linphone_core_manager_stop(LinphoneCoreManager *mgr){ + if (mgr->lc) { + linphone_core_destroy(mgr->lc); + mgr->lc=NULL; + } +} + +void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { + if (mgr->lc) linphone_core_destroy(mgr->lc); + if (mgr->identity) linphone_address_destroy(mgr->identity); + ms_free(mgr); +} + + +static void add_test_suite(test_suite_t *suite) { + if (test_suite == NULL) { + test_suite = (test_suite_t **)malloc(10 * sizeof(test_suite_t *)); + } + test_suite[nb_test_suites] = suite; + nb_test_suites++; + if ((nb_test_suites % 10) == 0) { + test_suite = (test_suite_t **)realloc(test_suite, (nb_test_suites + 10) * sizeof(test_suite_t *)); + } +} + +static int run_test_suite(test_suite_t *suite) { + int i; + + CU_pSuite pSuite = CU_add_suite(suite->name, suite->init_func, suite->cleanup_func); + + for (i = 0; i < suite->nb_tests; i++) { + if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) { + return CU_get_error(); + } + } + + return 0; +} + +int liblinphone_tester_test_suite_index(const char *suite_name) { + int i; + + for (i = 0; i < liblinphone_tester_nb_test_suites(); i++) { + if ((strcmp(suite_name, test_suite[i]->name) == 0) && (strlen(suite_name) == strlen(test_suite[i]->name))) { + return i; + } + } + + return -1; +} + +int liblinphone_tester_test_index(const char *suite_name, const char *test_name) { + int j,i; + + j = liblinphone_tester_test_suite_index(suite_name); + if(j != -1) { + for (i = 0; i < test_suite[j]->nb_tests; i++) { + if ((strcmp(test_name, test_suite[j]->tests[i].name) == 0) && (strlen(test_name) == strlen(test_suite[j]->tests[i].name))) { + return i; + } + } + } + + return -1; +} + +int liblinphone_tester_nb_test_suites(void) { + return nb_test_suites; +} + +int liblinphone_tester_nb_tests(const char *suite_name) { + int i = liblinphone_tester_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 = liblinphone_tester_test_suite_index(suite_name); + if ((suite_index < 0) || (suite_index >= liblinphone_tester_nb_test_suites())) return NULL; + if (test_index >= test_suite[suite_index]->nb_tests) return NULL; + return test_suite[suite_index]->tests[test_index].name; +} + +void liblinphone_tester_init(void) { + add_test_suite(&setup_test_suite); + add_test_suite(®ister_test_suite); + add_test_suite(&call_test_suite); + add_test_suite(&message_test_suite); + add_test_suite(&presence_test_suite); +#ifdef UPNP + add_test_suite(&upnp_test_suite); +#endif + add_test_suite(&stun_test_suite); + add_test_suite(&event_test_suite); + add_test_suite(&flexisip_test_suite); + add_test_suite(&remote_provisioning_test_suite); +} + +void liblinphone_tester_uninit(void) { + if (test_suite != NULL) { + free(test_suite); + test_suite = NULL; + nb_test_suites = 0; + } +} + +int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) { + int i; + int ret; + /* initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + for (i = 0; i < liblinphone_tester_nb_test_suites(); i++) { + run_test_suite(test_suite[i]); + } + + if (suite_name){ + CU_pSuite suite; + CU_basic_set_mode(CU_BRM_VERBOSE); + suite=CU_get_suite_by_name(suite_name, CU_get_registry()); + if (test_name) { + CU_pTest test=CU_get_test_by_name(test_name, suite); + CU_ErrorCode err= CU_basic_run_test(suite, test); + if (err != CUE_SUCCESS) ms_error("CU_basic_run_test error %d", err); + } else + CU_basic_run_suite(suite); + } else + { +#if HAVE_CU_CURSES + if (curses) { + /* Run tests using the CUnit curses interface */ + CU_curses_run_tests(); + } + else +#endif + { + /* Run all tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + } + } + + ret=CU_get_number_of_tests_failed()!=0; + CU_cleanup_registry(); + return ret; +} + From 042729508aae97c70d144eb378e0d763feb8691d Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 4 Mar 2014 15:38:20 +0100 Subject: [PATCH 303/439] Missing userhostsfile reference --- tester/liblinphone_tester.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 365d2b5f7..b3f2c98da 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -78,6 +78,7 @@ extern const char* auth_domain; extern const char* test_username; extern const char* test_password; extern const char* test_route; +extern const char* userhostsfile; typedef struct _stats { From eef680c35082a768c98d841299d16c49c03f0369 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 4 Mar 2014 16:00:41 +0100 Subject: [PATCH 304/439] Remove dependency on objc compiler, and let the final application in iOS use the liblinphonetester.a library to implement unit tests --- configure.ac | 1 - tester/Makefile.am | 9 +------ tester/liblinphonetester_ios.h | 24 ------------------ tester/liblinphonetester_ios.m | 46 ---------------------------------- 4 files changed, 1 insertion(+), 79 deletions(-) delete mode 100644 tester/liblinphonetester_ios.h delete mode 100644 tester/liblinphonetester_ios.m diff --git a/configure.ac b/configure.ac index 20148b3f6..9bbf1b359 100644 --- a/configure.ac +++ b/configure.ac @@ -39,7 +39,6 @@ AC_CONFIG_MACRO_DIR([m4]) dnl don't put anythingelse before AC_PROG_CC unless checking if macro still work for clang AC_PROG_CXX(["xcrun clang++" g++]) AC_PROG_CC(["xcrun clang" gcc]) -AC_PROG_OBJC(["xcrun clang" gcc]) gl_LD_OUTPUT_DEF diff --git a/tester/Makefile.am b/tester/Makefile.am index 95beaf139..fde5246c8 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -26,14 +26,7 @@ liblinphonetester_la_SOURCES = tester.c \ AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/coreapi AM_CFLAGS = $(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) -if BUILD_IOS - -#we build the liblinphonetester as a library, not as an executable, so that it is usable in XCode -liblinphonetester_la_OBJCFLAGS = $(AM_CFLAGS) -liblinphonetester_la_SOURCES += liblinphonetester_ios.m liblinphonetester_ios.h -liblinphonetester_la_LDFLAGS = -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation $(CUNIT_LIBS) - -else +if !BUILD_IOS noinst_PROGRAMS = liblinphone_tester diff --git a/tester/liblinphonetester_ios.h b/tester/liblinphonetester_ios.h deleted file mode 100644 index a3b6177c3..000000000 --- a/tester/liblinphonetester_ios.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - - -#include "ortp/ortp.h" - -int apple_start_tests(int argc, char* argv[]); - -void liblinphone_tester_ios_log_handler(OrtpLogLevel level, const char* fmt, va_list args); \ No newline at end of file diff --git a/tester/liblinphonetester_ios.m b/tester/liblinphonetester_ios.m deleted file mode 100644 index 8b853da51..000000000 --- a/tester/liblinphonetester_ios.m +++ /dev/null @@ -1,46 +0,0 @@ -/* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -#include "liblinphonetester_ios.h" - -#include -#import -#import - -extern int ios_tester_main(int argc, char * argv[]); - -int g_argc; -char** g_argv; - -static void* apple_main(void* data) { - ios_tester_main(g_argc,g_argv); - return NULL; -} - -int apple_start_tests(int argc, char* argv[]) -{ - pthread_t main_thread; - g_argc=argc; - g_argv=argv; - return (int)pthread_create(&main_thread,NULL,apple_main,NULL); -} - -void liblinphone_tester_ios_log_handler(OrtpLogLevel level, const char* fmt, va_list args) -{ - NSLogv([NSString stringWithUTF8String:fmt], args); -} From 8bc0b2e8a4f471325797cd67cb45055aedcf2cc3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 4 Mar 2014 16:28:23 +0100 Subject: [PATCH 305/439] Handle RTCP XR SDP attribute parsing and creation. --- coreapi/bellesip_sal/sal_sdp.c | 94 ++++++++++++++++++++++++++++++++-- include/sal/sal.h | 25 +++++++++ 2 files changed, 114 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 32a74a6ee..080a43dcc 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -68,6 +68,25 @@ 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_attribute_t * create_rtcp_xr_attribute(const SalRtcpXrDescription *desc) { + belle_sdp_rtcp_xr_attribute_t *attribute = belle_sdp_rtcp_xr_attribute_new(); + if (desc->rcvr_rtt_mode != SalRtcpXrRcvrRttNone) { + if (desc->rcvr_rtt_mode == SalRtcpXrRcvrRttAll) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "all"); + else if (desc->rcvr_rtt_mode == SalRtcpXrRcvrRttSender) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "sender"); + belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_max_size(attribute, desc->rcvr_rtt_max_size); + } + belle_sdp_rtcp_xr_attribute_set_stat_summary(attribute, (desc->stat_summary_enabled == TRUE)); + if (desc->stat_summary_enabled == TRUE) { + if (desc->stat_summary_flags & SalRtcpXrStatSummaryLoss) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "loss"); + if (desc->stat_summary_flags & SalRtcpXrStatSummaryDup) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "dup"); + if (desc->stat_summary_flags & SalRtcpXrStatSummaryJitt) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "jitt"); + if (desc->stat_summary_flags & SalRtcpXrStatSummaryTTL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "TTL"); + if (desc->stat_summary_flags & SalRtcpXrStatSummaryHL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "HL"); + } + belle_sdp_rtcp_xr_attribute_set_voip_metrics(attribute, (desc->voip_metrics_enabled == TRUE)); + return BELLE_SDP_ATTRIBUTE(attribute); +} + 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; @@ -194,7 +213,11 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMedia add_ice_remote_candidates(media_desc,stream); } } - + + if (stream->rtcp_xr.enabled == TRUE) { + belle_sdp_media_description_add_attribute(media_desc, create_rtcp_xr_attribute(&stream->rtcp_xr)); + } + return media_desc; } @@ -243,7 +266,11 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr if (desc->ice_completed == TRUE) belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("nortpproxy","yes")); if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd)); if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag)); - + + if (desc->rtcp_xr.enabled == TRUE) { + belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr)); + } + for ( i=0; in_total_streams; i++ ) { belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(desc,&desc->streams[i])); } @@ -325,7 +352,7 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med ms_message ( "Found: %d valid crypto lines", valid_count ); } -static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { +static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { belle_sip_list_t *attribute_it; const belle_sdp_attribute_t *attribute; const belle_sdp_raw_attribute_t *raw_attribute; @@ -373,6 +400,57 @@ static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_ } } +static void sal_init_rtcp_xr_description(SalRtcpXrDescription *desc) { + desc->enabled = FALSE; + desc->rcvr_rtt_mode = SalRtcpXrRcvrRttNone; + desc->rcvr_rtt_max_size = -1; + desc->stat_summary_flags = 0; + desc->voip_metrics_enabled = FALSE; +} + +static void sdp_parse_rtcp_xr_parameters(const belle_sdp_attribute_t *attribute, SalRtcpXrDescription *desc) { + sal_init_rtcp_xr_description(desc); + + if (attribute != NULL) { + const belle_sdp_rtcp_xr_attribute_t *xr_attr = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute); + const char *rcvr_rtt_mode = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(xr_attr); + if (rcvr_rtt_mode != NULL) { + if (strcasecmp(rcvr_rtt_mode, "all") == 0) { + desc->rcvr_rtt_mode = SalRtcpXrRcvrRttAll; + } else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) { + desc->rcvr_rtt_mode = SalRtcpXrRcvrRttSender; + } + desc->rcvr_rtt_max_size = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(xr_attr); + } + desc->stat_summary_enabled = (belle_sdp_rtcp_xr_attribute_has_stat_summary(xr_attr) != 0); + if (desc->stat_summary_enabled) { + belle_sip_list_t *stat_summary_flag_it; + for (stat_summary_flag_it = belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(xr_attr); stat_summary_flag_it != NULL; stat_summary_flag_it = stat_summary_flag_it->next ) { + const char *flag = (const char *)stat_summary_flag_it->data; + if (flag != NULL) { + if (strcasecmp(flag, "loss") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryLoss; + else if (strcasecmp(flag, "dup") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryDup; + else if (strcasecmp(flag, "jitt") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryJitt; + else if (strcasecmp(flag, "TTL") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryTTL; + else if (strcasecmp(flag, "HL") == 0) desc->stat_summary_flags |= SalRtcpXrStatSummaryHL; + } + } + } + desc->voip_metrics_enabled = (belle_sdp_rtcp_xr_attribute_has_voip_metrics(xr_attr) != 0); + desc->enabled = TRUE; + } +} + +static void sdp_parse_session_rtcp_xr_parameters(belle_sdp_session_description_t *session_desc, SalRtcpXrDescription *desc) { + const belle_sdp_attribute_t *attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr"); + sdp_parse_rtcp_xr_parameters(attribute, desc); +} + +static void sdp_parse_media_rtcp_xr_parameters(belle_sdp_media_description_t *media_desc, SalRtcpXrDescription *desc) { + const belle_sdp_attribute_t *attribute = belle_sdp_media_description_get_attribute(media_desc, "rtcp-xr"); + sdp_parse_rtcp_xr_parameters(attribute, desc); +} + static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, belle_sdp_media_description_t *media_desc) { SalStreamDescription *stream; belle_sdp_connection_t* cnx; @@ -459,7 +537,10 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, } /* Get ICE candidate attributes if any */ - sdp_parse_ice_media_parameters(media_desc, stream); + sdp_parse_media_ice_parameters(media_desc, stream); + + /* Get RTCP-XR attributes if any */ + sdp_parse_media_rtcp_xr_parameters(media_desc, &stream->rtcp_xr); md->n_total_streams++; return stream; @@ -508,7 +589,10 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); if (value) desc->ice_lite = TRUE; - + + /* Get session RTCP-XR attributes if any */ + sdp_parse_session_rtcp_xr_parameters(session_desc, &desc->rtcp_xr); + for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc ) ; media_desc_it!=NULL ; media_desc_it=media_desc_it->next ) { diff --git a/include/sal/sal.h b/include/sal/sal.h index 0fa968eb2..ccb013b85 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -135,6 +135,20 @@ typedef enum{ }SalStreamDir; const char* sal_stream_dir_to_string(SalStreamDir type); +typedef enum { + SalRtcpXrRcvrRttNone, + SalRtcpXrRcvrRttAll, + SalRtcpXrRcvrRttSender +} SalRtcpXrRcvrRttMode; + +typedef enum { + SalRtcpXrStatSummaryLoss = (1 << 0), + SalRtcpXrStatSummaryDup = (1 << 1), + SalRtcpXrStatSummaryJitt = (1 << 2), + SalRtcpXrStatSummaryTTL = (1 << 3), + SalRtcpXrStatSummaryHL = (1 << 4) +} SalRtcpXrStatSummaryFlag; + #define SAL_ENDPOINT_CANDIDATE_MAX 2 @@ -176,6 +190,15 @@ typedef struct SalSrtpCryptoAlgo { #define SAL_CRYPTO_ALGO_MAX 4 +typedef struct SalRtcpXrDescription { + bool_t enabled; + bool_t stat_summary_enabled; + bool_t voip_metrics_enabled; + SalRtcpXrRcvrRttMode rcvr_rtt_mode; + int rcvr_rtt_max_size; + SalRtcpXrStatSummaryFlag stat_summary_flags; +} SalRtcpXrDescription; + typedef struct SalStreamDescription{ char name[16]; /*unique name of stream, in order to ease offer/answer model algorithm*/ SalMediaProto proto; @@ -193,6 +216,7 @@ typedef struct SalStreamDescription{ SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX]; unsigned int crypto_local_tag; int max_rate; + SalRtcpXrDescription rtcp_xr; SalIceCandidate ice_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES]; SalIceRemoteCandidate ice_remote_candidates[SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES]; char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; @@ -219,6 +243,7 @@ typedef struct SalMediaDescription{ unsigned int session_id; SalStreamDir dir; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; + SalRtcpXrDescription rtcp_xr; char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN]; bool_t ice_lite; From 6734882dc88bc6ea2ad1ca604de6fbbc7aa25e6c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 4 Mar 2014 17:57:21 +0100 Subject: [PATCH 306/439] Put the libraries in the good order for static linking. --- tester/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/Makefile.am b/tester/Makefile.am index fde5246c8..85a6f9c48 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -32,7 +32,7 @@ noinst_PROGRAMS = liblinphone_tester liblinphone_tester_LDFLAGS = $(CUNIT_LIBS) liblinphone_tester_SOURCES = liblinphone_tester.c -liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la $(BELLESIP_LIBS) $(LIBXML2_LIBS) liblinphonetester.la +liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la liblinphonetester.la $(SIPSTACK_LIBS) $(LIBXML2_LIBS) endif From 95030951d11d8d0b0c441cd3bef267c453cd05e5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 4 Mar 2014 22:57:53 +0100 Subject: [PATCH 307/439] add new function to play a file locally, in or out of calls. add new function to define a tone or wav file to be played automatically upon call errors --- coreapi/bellesip_sal/sal_op_impl.c | 60 +++++++++++++++------ coreapi/callbacks.c | 3 +- coreapi/ec-calibrator.c | 4 +- coreapi/linphonecore.c | 75 +++++++++++++++++++++++--- coreapi/linphonecore.h | 20 +++++-- coreapi/lsd.c | 4 +- coreapi/misc.c | 82 +++++++++++++++++++++++++++-- coreapi/private.h | 33 ++++++++---- gtk/chat.c | 1 + gtk/linphone.h | 1 + gtk/support.c | 21 ++++++++ include/sal/sal.h | 9 +++- mediastreamer2 | 2 +- share/Makefile.am | 2 +- share/incoming_chat.wav | Bin 0 -> 51244 bytes 15 files changed, 269 insertions(+), 48 deletions(-) create mode 100644 share/incoming_chat.wav diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index d7b6c0c1d..481fb4cbd 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -375,70 +375,98 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonNoMatch: ret=481; break; + case SalReasonRequestTimeout: + ret=408; + break; + case SalReasonMovedPermanently: + ret=301; + break; + case SalReasonGone: + ret=410; + break; + case SalReasonAddressIncomplete: + ret=484; + break; + case SalReasonNotImplemented: + ret=501; + break; + case SalReasonServerTimeout: + ret=504; + break; + case SalReasonBadGateway: + ret=502; + break; } return ret; } void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { + *sal_err=SalErrorFailure; switch(code) { + case 301: + *sal_reason=SalReasonMovedPermanently; + break; case 302: *sal_reason=SalReasonRedirect; - *sal_err=SalErrorFailure; - break; - case 400: - *sal_err=SalErrorUnknown; break; case 401: case 407: - *sal_err=SalErrorFailure; *sal_reason=SalReasonUnauthorized; break; case 403: - *sal_err=SalErrorFailure; *sal_reason=SalReasonForbidden; break; case 404: - *sal_err=SalErrorFailure; *sal_reason=SalReasonNotFound; break; + case 408: + *sal_reason=SalReasonRequestTimeout; + break; + case 410: + *sal_reason=SalReasonGone; + break; case 415: - *sal_err=SalErrorFailure; *sal_reason=SalReasonUnsupportedContent; break; case 422: ms_error ("422 not implemented yet");; break; case 480: - *sal_err=SalErrorFailure; *sal_reason=SalReasonTemporarilyUnavailable; break; case 481: - *sal_err=SalErrorFailure; *sal_reason=SalReasonNoMatch; + break; + case 484: + *sal_reason=SalReasonAddressIncomplete; + break; case 486: - *sal_err=SalErrorFailure; *sal_reason=SalReasonBusy; break; case 487: break; case 488: - *sal_err=SalErrorFailure; *sal_reason=SalReasonNotAcceptable; break; case 491: - *sal_err=SalErrorFailure; *sal_reason=SalReasonRequestPending; break; + case 501: + *sal_reason=SalReasonNotImplemented; + break; + case 502: + *sal_reason=SalReasonBadGateway; + break; + case 504: + *sal_reason=SalReasonServerTimeout; + 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: diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 1da9b56a9..55685af59 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -721,9 +721,8 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); }else{ linphone_call_set_state(call,LinphoneCallError,details); - if (sr==SalReasonBusy) - linphone_core_play_named_tone(lc,LinphoneToneBusy); } + linphone_core_play_call_error_tone(lc,call->reason); if (referer){ /*notify referer of the failure*/ diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index dbb6d857a..bff0a00f1 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -154,7 +154,7 @@ static void ecc_play_tones(EcCalibrator *ecc){ memset(&tone,0,sizeof(tone)); memset(&expected_tone,0,sizeof(expected_tone)); - ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc); + ms_filter_add_notify_callback(ecc->det,on_tone_received,ecc,TRUE); /* configure the tones to be scanned */ @@ -188,7 +188,7 @@ static void ecc_play_tones(EcCalibrator *ecc){ ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_sleep(2); - ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc); + ms_filter_add_notify_callback(ecc->gen,on_tone_sent,ecc,TRUE); /* play the three tones*/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ca770b15e..be418d2dd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -609,6 +609,8 @@ static void sound_config_read(LinphoneCore *lc) /*just parse requested stream feature once at start to print out eventual errors*/ linphone_core_get_audio_features(lc); + + _linphone_core_set_call_error_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL); } static void certificates_config_read(LinphoneCore *lc) @@ -5356,17 +5358,24 @@ void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ } } +typedef enum{ + LinphoneToneGenerator, + LinphoneLocalPlayer +}LinphoneAudioResourceType; -static MSFilter *get_dtmf_gen(LinphoneCore *lc){ +static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType rtype){ LinphoneCall *call=linphone_core_get_current_call (lc); AudioStream *stream=NULL; + RingStream *ringstream; if (call){ stream=call->audiostream; }else if (linphone_core_is_in_conference(lc)){ stream=lc->conf_ctx.local_participant; } if (stream){ - return stream->dtmfgen; + if (rtype==LinphoneToneGenerator) return stream->dtmfgen; + if (rtype==LinphoneLocalPlayer) return stream->local_player; + return NULL; } if (lc->ringstream==NULL){ float amp=lp_config_get_float(lc->config,"sound","dtmf_player_amp",0.1); @@ -5374,14 +5383,21 @@ static MSFilter *get_dtmf_gen(LinphoneCore *lc){ if (ringcard == NULL) return NULL; - lc->ringstream=ring_start(NULL,0,ringcard); + ringstream=lc->ringstream=ring_start(NULL,0,ringcard); ms_filter_call_method(lc->ringstream->gendtmf,MS_DTMF_GEN_SET_DEFAULT_AMPLITUDE,&); lc->dmfs_playing_start_time=time(NULL); }else{ + ringstream=lc->ringstream; if (lc->dmfs_playing_start_time!=0) lc->dmfs_playing_start_time=time(NULL); } - return lc->ringstream->gendtmf; + if (rtype==LinphoneToneGenerator) return ringstream->gendtmf; + if (rtype==LinphoneLocalPlayer) return ringstream->source; + return NULL; +} + +static MSFilter *get_dtmf_gen(LinphoneCore *lc){ + return get_audio_resource(lc,LinphoneToneGenerator); } /** @@ -5403,6 +5419,26 @@ void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf); } +/** + * Plays an audio file to the local user. + * This function works at any time, during calls, or when no calls are running. + * It doesn't request the underlying audio system to support multiple playback streams. + * @param lc the linphone core + * @param audiofile path to audio file in wav PCM 16 bit format. + * @ingroup misc +**/ +int linphone_core_play_local(LinphoneCore *lc, const char *audiofile){ + MSFilter *f=get_audio_resource(lc,LinphoneLocalPlayer); + int loopms=-1; + if (!f) return -1; + ms_filter_call_method(f,MS_PLAYER_SET_LOOP,&loopms); + if (ms_filter_call_method(f,MS_PLAYER_OPEN,(void*)audiofile)!=0){ + return -1; + } + ms_filter_call_method_noarg(f,MS_PLAYER_START); + return 0; +} + void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ if (linphone_core_tone_indications_enabled(lc)){ MSFilter *f=get_dtmf_gen(lc); @@ -5443,6 +5479,19 @@ void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ } } +void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason){ + if (linphone_core_tone_indications_enabled(lc)){ + LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason); + if (tone){ + if (tone->audiofile){ + linphone_core_play_local(lc,tone->audiofile); + }else if (tone->toneid!=LinphoneToneUndefined){ + linphone_core_play_named_tone(lc,tone->toneid); + } + } + } +} + /** * @ingroup media_parameters * @@ -5672,7 +5721,7 @@ static void sound_config_uninit(LinphoneCore *lc) if (config->local_ring) ms_free(config->local_ring); if (config->remote_ring) ms_free(config->remote_ring); - + lc->tones=ms_list_free_with_data(lc->tones, (void (*)(void*))linphone_tone_description_destroy); } static void video_config_uninit(LinphoneCore *lc) @@ -6057,7 +6106,7 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "No error"; case LinphoneReasonNoResponse: return "No response"; - case LinphoneReasonBadCredentials: + case LinphoneReasonForbidden: return "Bad credentials"; case LinphoneReasonDeclined: return "Call declined"; @@ -6079,6 +6128,20 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "Not acceptable here"; case LinphoneReasonNoMatch: return "No match"; + case LinphoneReasonMovedPermanently: + return "Moved permanently"; + case LinphoneReasonGone: + return "Gone"; + case LinphoneReasonTemporarilyUnavailable: + return "Temporarily unavailable"; + case LinphoneReasonAddressIncomplete: + return "Address incomplete"; + case LinphoneReasonNotImplemented: + return "Not implemented"; + case LinphoneReasonBadGateway: + return "Bad gateway"; + case LinphoneReasonServerTimeout: + return "Server timeout"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f70a13ad0..32a092176 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -164,19 +164,28 @@ typedef struct _LinphoneCall LinphoneCall; enum _LinphoneReason{ LinphoneReasonNone, LinphoneReasonNoResponse, /**player,lsd_player_on_eop,b); + ms_filter_add_notify_callback (b->player,lsd_player_on_eop,b,FALSE); lsd_player_configure(b); ms_filter_call_method_noarg (b->player,MS_PLAYER_START); return 0; @@ -249,7 +249,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, mp.pin=0; lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd); - ms_filter_set_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0]); + ms_filter_add_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0],FALSE); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID,lsd); diff --git a/coreapi/misc.c b/coreapi/misc.c index c64d51160..a61809464 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1099,13 +1099,13 @@ SalReason linphone_reason_to_sal(LinphoneReason reason){ return SalReasonUnknown; case LinphoneReasonNoResponse: return SalReasonUnknown; - case LinphoneReasonBadCredentials: + case LinphoneReasonForbidden: return SalReasonForbidden; case LinphoneReasonDeclined: return SalReasonDeclined; case LinphoneReasonNotFound: return SalReasonNotFound; - case LinphoneReasonNotAnswered: + case LinphoneReasonTemporarilyUnavailable: return SalReasonTemporarilyUnavailable; case LinphoneReasonBusy: return SalReasonBusy; @@ -1121,6 +1121,20 @@ SalReason linphone_reason_to_sal(LinphoneReason reason){ return SalReasonUnsupportedContent; case LinphoneReasonNoMatch: return SalReasonNoMatch; + case LinphoneReasonMovedPermanently: + return SalReasonMovedPermanently; + case LinphoneReasonGone: + return SalReasonGone; + case LinphoneReasonAddressIncomplete: + return SalReasonAddressIncomplete; + case LinphoneReasonNotImplemented: + return SalReasonNotImplemented; + case LinphoneReasonBadGateway: + return SalReasonBadGateway; + case LinphoneReasonServerTimeout: + return SalReasonServerTimeout; + case LinphoneReasonNotAnswered: + return SalReasonRequestTimeout; } return SalReasonUnknown; } @@ -1153,7 +1167,7 @@ LinphoneReason linphone_reason_from_sal(SalReason r){ ret=LinphoneReasonNone; break; case SalReasonTemporarilyUnavailable: - ret=LinphoneReasonNone; + ret=LinphoneReasonTemporarilyUnavailable; break; case SalReasonServiceUnavailable: ret=LinphoneReasonIOError; @@ -1170,6 +1184,27 @@ LinphoneReason linphone_reason_from_sal(SalReason r){ case SalReasonNoMatch: ret=LinphoneReasonNoMatch; break; + case SalReasonRequestTimeout: + ret=LinphoneReasonNotAnswered; + break; + case SalReasonMovedPermanently: + ret=LinphoneReasonMovedPermanently; + break; + case SalReasonGone: + ret=LinphoneReasonGone; + break; + case SalReasonAddressIncomplete: + ret=LinphoneReasonAddressIncomplete; + break; + case SalReasonNotImplemented: + ret=LinphoneReasonNotImplemented; + break; + case SalReasonBadGateway: + ret=LinphoneReasonBadGateway; + break; + case SalReasonServerTimeout: + ret=LinphoneReasonServerTimeout; + break; } return ret; } @@ -1275,4 +1310,45 @@ int linphone_core_migrate_to_multi_transport(LinphoneCore *lc){ return 0; } +LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile){ + LinphoneToneDescription *obj=ms_new0(LinphoneToneDescription,1); + obj->reason=reason; + obj->toneid=id; + obj->audiofile=audiofile ? ms_strdup(audiofile) : NULL; + return obj; +} +void linphone_tone_description_destroy(LinphoneToneDescription *obj){ + if (obj->audiofile) ms_free(obj->audiofile); + ms_free(obj); +} + +LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason){ + const MSList *elem; + for (elem=lc->tones;elem!=NULL;elem=elem->next){ + LinphoneToneDescription *tone=(LinphoneToneDescription*)elem->data; + if (tone->reason==reason) return tone; + } + return NULL; +} + +void _linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile){ + LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason); + if (tone){ + lc->tones=ms_list_remove(lc->tones,tone); + linphone_tone_description_destroy(tone); + } + tone=linphone_tone_description_new(reason,id,audiofile); + lc->tones=ms_list_append(lc->tones,tone); +} + +/** + * Assign an audio file to played locally upon call failure, for a given reason. + * @param lc the core + * @param reason the #LinphoneReason representing the failure error code. + * @param audiofile a wav file to be played when such call failure happens. + * @ingroup misc +**/ +void linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, const char *audiofile){ + _linphone_core_set_call_error_tone(lc,reason,LinphoneToneUndefined, audiofile); +} diff --git a/coreapi/private.h b/coreapi/private.h index 21a62e334..7539e3bca 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -343,8 +343,6 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing); -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); @@ -588,6 +586,26 @@ struct _LinphoneConference{ bool_t local_muted; }; +typedef enum _LinphoneToneID{ + LinphoneToneUndefined, + LinphoneToneBusy, + LinphoneToneCallWaiting, + LinphoneToneCallOnHold, + LinphoneToneCallFailed +}LinphoneToneID; + +typedef struct _LinphoneToneDescription{ + LinphoneReason reason; + LinphoneToneID toneid; + char *audiofile; +}LinphoneToneDescription; + +LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile); +void linphone_tone_description_destroy(LinphoneToneDescription *obj); +LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason); +void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason); +void _linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile); + typedef struct _LinphoneConference LinphoneConference; struct _LinphoneCore @@ -653,10 +671,10 @@ struct _LinphoneCore bool_t use_preview_window; time_t network_last_check; + bool_t network_last_status; - bool_t ringstream_autorelease; - bool_t pad[3]; + bool_t pad[2]; int device_rotation; int max_calls; LinphoneTunnel *tunnel; @@ -670,6 +688,7 @@ struct _LinphoneCore UpnpContext *upnp; #endif //BUILD_UPNP belle_http_provider_t *http_provider; + MSList *tones; }; @@ -779,12 +798,6 @@ void linphone_chat_message_store_state(LinphoneChatMessage *msg); void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); -typedef enum _LinphoneToneID{ - LinphoneToneBusy, - LinphoneToneCallWaiting, - LinphoneToneCallOnHold, - LinphoneToneCallFailed -}LinphoneToneID; void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); const char *linphone_core_create_uuid(LinphoneCore *lc); diff --git a/gtk/chat.c b/gtk/chat.c index 0c9aa400b..9f6e21943 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -528,6 +528,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, linphone_gtk_push_text ( w,linphone_chat_message_get_from ( msg ), FALSE,room,msg,FALSE ); } + linphone_core_play_local(lc,linphone_gtk_get_sound_path("incoming_chat.wav")); linphone_gtk_show_friends(); } diff --git a/gtk/linphone.h b/gtk/linphone.h index 7c85367bc..e1df87ab3 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -170,4 +170,5 @@ void linphone_gtk_schedule_restart(void); void linphone_gtk_set_configuration_uri(void); GtkWidget * linphone_gtk_show_config_fetching(void); void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state); +const char *linphone_gtk_get_sound_path(const char *file); diff --git a/gtk/support.c b/gtk/support.c index de6c3a910..81754bb45 100644 --- a/gtk/support.c +++ b/gtk/support.c @@ -203,6 +203,27 @@ void linphone_gtk_set_ui_config(const char *key , const char * val){ lp_config_set_string(cfg,"GtkUi",key,val); } +const char *linphone_gtk_get_sound_path(const char *name){ + static char *ret=NULL; + const char *file; + file=linphone_gtk_get_ui_config(name,NULL); + if (file==NULL){ + char *dirname=g_path_get_dirname(name); + if (strcmp(dirname,".")!=0){ + g_free(dirname); + return name; + } + g_free(dirname); + file=name; + } + if (ret){ + g_free(ret); + ret=NULL; + } + ret=g_build_filename(PACKAGE_SOUND_DIR,name,NULL); + return ret; +} + static void parse_item(const char *item, const char *window_name, GtkWidget *w, gboolean show){ char tmp[64]; char *dot; diff --git a/include/sal/sal.h b/include/sal/sal.h index ccb013b85..7bbdb0d0a 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -314,6 +314,7 @@ typedef enum SalReason{ SalReasonBusy, SalReasonRedirect, SalReasonTemporarilyUnavailable, + SalReasonRequestTimeout, SalReasonNotFound, SalReasonDoNotDisturb, SalReasonUnsupportedContent, @@ -323,7 +324,13 @@ typedef enum SalReason{ SalReasonRequestPending, SalReasonUnauthorized, SalReasonNotAcceptable, - SalReasonNoMatch /*equivalent to 481 Transaction/Call leg does not exist*/ + SalReasonNoMatch, /*equivalent to 481 Transaction/Call leg does not exist*/ + SalReasonMovedPermanently, + SalReasonGone, + SalReasonAddressIncomplete, + SalReasonNotImplemented, + SalReasonBadGateway, + SalReasonServerTimeout }SalReason; const char* sal_reason_to_string(const SalReason reason); diff --git a/mediastreamer2 b/mediastreamer2 index 0e6be4c7c..9cd81464a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0e6be4c7cad7ce3d3cb4feed9a6ad52439ba365e +Subproject commit 9cd81464a916a95a5e4157276ae661d68ed3a7ee diff --git a/share/Makefile.am b/share/Makefile.am index 85c1ab11b..63f15dfe4 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS=C fr it ja cs xml -LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav +LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav incoming_chat.wav LINPHONE_RINGS=rings/orig.wav \ rings/oldphone.wav \ rings/oldphone-mono.wav \ diff --git a/share/incoming_chat.wav b/share/incoming_chat.wav new file mode 100644 index 0000000000000000000000000000000000000000..99a2e7dfcb9cef9225764bad3a2eeaae94ce5484 GIT binary patch literal 51244 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 e_QW_mRTwz2!zd%WKvXx%mIL>i+;tK Date: Tue, 4 Mar 2014 23:08:11 +0100 Subject: [PATCH 308/439] add incoming chat wav to mac bundle --- build/macos/linphone.bundle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/macos/linphone.bundle b/build/macos/linphone.bundle index 8008007ce..8896fa7d3 100644 --- a/build/macos/linphone.bundle +++ b/build/macos/linphone.bundle @@ -171,6 +171,10 @@ ${prefix:linphone}/share/sounds/linphone/ringback.wav + + + ${prefix:linphone}/share/sounds/linphone/incoming_chat.wav + + + False + 12 + + + + + + + + + + + + + + diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 8f96cfb27..bdf54ec24 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -567,13 +567,6 @@ static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){ return TRUE; } -typedef struct _volume_ctx{ - GtkWidget *widget; - get_volume_t get_volume; - void *data; - float last_value; -}volume_ctx_t; - #define UNSIGNIFICANT_VOLUME (-26) #define SMOOTH 0.15 diff --git a/gtk/linphone.h b/gtk/linphone.h index e1df87ab3..910981a53 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -53,6 +53,27 @@ enum { COMPLETION_LDAP }; +typedef float (*get_volume_t)(void *data); + +typedef struct _volume_ctx{ + GtkWidget *widget; + get_volume_t get_volume; + void *data; + float last_value; +}volume_ctx_t; + +typedef enum { + CAP_IGNORE, + CAP_PLAYBACK, + CAP_CAPTURE +}DeviceCap; + +enum { + START_LINPHONE, + START_AUDIO_ASSISTANT, + START_LINPHONE_WITH_CALL +}; + GdkPixbuf * create_pixbuf(const gchar *filename); GdkPixbufAnimation *create_pixbuf_animation(const gchar *filename); void add_pixmap_directory(const gchar *directory); @@ -96,7 +117,6 @@ LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void); void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap); int linphone_gtk_is_ldap_supported(void); - void linphone_gtk_open_browser(const char *url); void linphone_gtk_check_for_new_version(void); const char *linphone_gtk_get_lang(const char *config_file); @@ -150,8 +170,8 @@ void linphone_gtk_unset_from_conference(LinphoneCall *call); void linphone_gtk_terminate_conference_participant(LinphoneCall *call); void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call); void linphone_gtk_update_video_button(LinphoneCall *call); -typedef float (*get_volume_t)(void *data); void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data); +void linphone_gtk_uninit_audio_meter(GtkWidget *w); void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login); void linphone_gtk_exit_login_frame(void); @@ -159,14 +179,17 @@ void linphone_gtk_set_ui_config(const char *key, const char *value); void linphone_gtk_log_uninit(); -bool_t linphone_gtk_init_instance(const char *app_name, const char *addr_to_call); +bool_t linphone_gtk_init_instance(const char *app_name, int option, const char *addr_to_call); void linphone_gtk_uninit_instance(void); void linphone_gtk_monitor_usb(void); void linphone_gtk_unmonitor_usb(void); +void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap); gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference); void linphone_gtk_schedule_restart(void); +void linphone_gtk_show_audio_assistant(void); + void linphone_gtk_set_configuration_uri(void); GtkWidget * linphone_gtk_show_config_fetching(void); void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state); diff --git a/gtk/main.c b/gtk/main.c index f40acb8b6..347abafce 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -86,8 +86,10 @@ static gboolean verbose=0; static gboolean quit_done=FALSE; static gboolean auto_answer = 0; static gchar * addr_to_call = NULL; +static int start_option = START_LINPHONE; static gboolean no_video=FALSE; static gboolean iconified=FALSE; +static gboolean run_audio_assistant=FALSE; static gchar *workingdir=NULL; static char *progpath=NULL; gchar *linphone_logfile=NULL; @@ -153,6 +155,13 @@ static GOptionEntry linphone_options[]={ .arg_data = (gpointer) &custom_config_file, .description = N_("Configuration file") }, + { + .long_name = "run-audio-assistant", + .short_name = '\0', + .arg = G_OPTION_ARG_NONE, + .arg_data = (gpointer) &run_audio_assistant, + .description = N_("Run the audio assistant") + }, {0} }; @@ -2136,6 +2145,11 @@ static void linphone_gtk_init_ui(void){ } #endif + if(run_audio_assistant){ + linphone_gtk_show_audio_assistant(); + start_option=START_AUDIO_ASSISTANT; + iconified = TRUE; + } #ifndef HAVE_GTK_OSX linphone_gtk_init_status_icon(); #endif @@ -2168,7 +2182,6 @@ int main(int argc, char *argv[]){ config_file=linphone_gtk_get_config_file(NULL); - #ifdef WIN32 /*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */ if ((lang=getenv("LANG"))!=NULL){ @@ -2226,6 +2239,9 @@ int main(int argc, char *argv[]){ } config_file=linphone_gtk_get_config_file(custom_config_file); + if(run_audio_assistant) start_option=START_AUDIO_ASSISTANT; + if(addr_to_call != NULL) start_option=START_LINPHONE_WITH_CALL; + settings=gtk_settings_get_default(); g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM)); g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON)); @@ -2275,7 +2291,7 @@ int main(int argc, char *argv[]){ #endif core_start: - if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){ + if (linphone_gtk_init_instance(app_name, start_option, addr_to_call) == FALSE){ g_warning("Another running instance of linphone has been detected. It has been woken-up."); g_warning("This instance is going to exit now."); gdk_threads_leave(); diff --git a/gtk/main.ui b/gtk/main.ui index 8be5b3555..44750d572 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -786,6 +786,12 @@ False gtk-add
+ + True + False + 0.49000000953674316 + gtk-properties + True False @@ -821,6 +827,59 @@ False gtk-add + + + + + + + + All users + + + Online users + + + + + + + + + + + ADSL + + + Fiber Channel + + + + + + + + + + + Default + + + + + + + + + + + ADSL + + + Fiber Channel + + + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -991,6 +1050,17 @@
+ + + Audio assistant + True + False + False + image21 + False + + +
@@ -1733,9 +1803,6 @@ 5
- - - False @@ -1762,6 +1829,9 @@ 3 + + +
@@ -1881,59 +1951,6 @@
- - - - - - - - All users - - - Online users - - - - - - - - - - - ADSL - - - Fiber Channel - - - - - - - - - - - Default - - - - - - - - - - - ADSL - - - Fiber Channel - - - True False diff --git a/gtk/propertybox.c b/gtk/propertybox.c index b2b54715f..494f1a5fb 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -21,13 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone_tunnel.h" #include "lpconfig.h" -typedef enum { - CAP_IGNORE, - CAP_PLAYBACK, - CAP_CAPTURE -}DeviceCap; - -static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap){ +void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap){ const char **p=devices; int i=0,active=-1; GtkTreeModel *model; diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c index b418b7104..27f7363b7 100644 --- a/gtk/setupwizard.c +++ b/gtk/setupwizard.c @@ -81,7 +81,7 @@ static void linphone_account_informations_changed(GtkEntry *entry, GtkWidget *w) GtkEntry* username = GTK_ENTRY(g_object_get_data(G_OBJECT(w),"username")); gtk_assistant_set_page_complete(GTK_ASSISTANT(assistant),w, - gtk_entry_get_text_length(username) >= LOGIN_MIN_SIZE); + gtk_entry_get_text_length(username) > 0); } static GtkWidget *create_linphone_account_informations_page() { @@ -453,6 +453,7 @@ static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page static gint destroy_assistant(GtkWidget* w){ gtk_widget_destroy(w); + the_assistant = NULL; return FALSE; } diff --git a/gtk/singleinstance.c b/gtk/singleinstance.c index 5bb70c002..e78f6ac6a 100644 --- a/gtk/singleinstance.c +++ b/gtk/singleinstance.c @@ -33,11 +33,26 @@ gchar *make_name(const char *appname){ return g_strdup(appname); } -static gboolean execute_wakeup(char *uri){ - linphone_gtk_show_main_window(); - if (strlen(uri)>0) - linphone_gtk_refer_received(linphone_gtk_get_core(),uri); - g_free(uri); +static gboolean execute_wakeup(char *buf){ + char uri[255]={0}; + int option; + + if (strlen(buf)>1) sscanf(buf,"%i%s",&option,uri); + else sscanf(buf,"%i",&option); + + switch(option){ + case START_LINPHONE: + linphone_gtk_show_main_window(); + break; + case START_AUDIO_ASSISTANT: + linphone_gtk_show_audio_assistant(); + break; + case START_LINPHONE_WITH_CALL: + linphone_gtk_refer_received(linphone_gtk_get_core(),uri); + break; + }; + + g_free(buf); return FALSE; } @@ -71,14 +86,16 @@ static void linphone_gtk_init_pipe(const char *name){ ms_thread_create(&pipe_thread,NULL,server_pipe_thread,NULL); } -bool_t linphone_gtk_init_instance(const char *app_name, const char *addr_to_call){ +bool_t linphone_gtk_init_instance(const char *app_name, int option, const char *addr_to_call){ pipe_name=make_name(app_name); ortp_pipe_t p=ortp_client_pipe_connect(pipe_name); if (p!=(ortp_pipe_t)-1){ uint8_t buf[256]={0}; g_message("There is already a running instance."); if (addr_to_call!=NULL){ - strncpy((char*)buf,addr_to_call,sizeof(buf)-1); + sprintf((char *)buf,"%i%s",option,addr_to_call); + } else { + sprintf((char *)buf,"%i",option); } if (ortp_pipe_write(p,buf,sizeof(buf))==-1){ g_error("Fail to send wakeup command to running instance: %s",strerror(errno)); From 269f8d1c4ee1b587a262e407891224471ae2ad20 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 21 Mar 2014 18:13:54 +0100 Subject: [PATCH 358/439] add new API to obtain full details about failures (calls, registration, events). Fix bug when receiving a 487 after cancelling call, resulting in a call waiting tone to be played. --- coreapi/bellesip_sal/sal_impl.c | 25 +-- coreapi/bellesip_sal/sal_impl.h | 9 +- coreapi/bellesip_sal/sal_op_call.c | 38 ++-- coreapi/bellesip_sal/sal_op_events.c | 23 +- coreapi/bellesip_sal/sal_op_impl.c | 168 ++++++++------- coreapi/bellesip_sal/sal_op_message.c | 43 ++-- coreapi/bellesip_sal/sal_op_presence.c | 26 ++- coreapi/bellesip_sal/sal_op_publish.c | 24 ++- coreapi/bellesip_sal/sal_op_registration.c | 7 +- coreapi/callbacks.c | 231 ++++++++++----------- coreapi/chat.c | 13 +- coreapi/event.c | 6 +- coreapi/event.h | 5 + coreapi/linphonecall.c | 23 +- coreapi/linphonecore.c | 10 +- coreapi/linphonecore.h | 25 ++- coreapi/misc.c | 56 ++++- coreapi/private.h | 14 +- coreapi/proxy.c | 6 +- include/sal/sal.h | 36 ++-- tester/call_tester.c | 4 +- 21 files changed, 451 insertions(+), 341 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 47242cdd5..be3c9ba17 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -162,8 +162,8 @@ 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_event_get_dialog(event); SalOp* op = belle_sip_dialog_get_application_data(dialog); - if (op && op->callbacks.process_dialog_terminated) { - op->callbacks.process_dialog_terminated(op,event); + if (op && op->callbacks && op->callbacks->process_dialog_terminated) { + op->callbacks->process_dialog_terminated(op,event); } else { ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog); } @@ -177,8 +177,8 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); /*also reset auth count on IO error*/ op->auth_requests=0; - if (op->callbacks.process_io_error) { - op->callbacks.process_io_error(op,event); + if (op->callbacks && op->callbacks->process_io_error) { + op->callbacks->process_io_error(op,event); } } else { /*ms_error("sal process_io_error not implemented yet for non transaction");*/ @@ -290,8 +290,8 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve sal_op_set_privacy_from_message(op,(belle_sip_message_t*)req); sal_op_assign_recv_headers(op,(belle_sip_message_t*)req); - if (op->callbacks.process_request_event) { - op->callbacks.process_request_event(op,event); + if (op->callbacks && op->callbacks->process_request_event) { + op->callbacks->process_request_event(op,event); } else { ms_error("sal process_request_event not implemented yet"); } @@ -329,7 +329,7 @@ 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->callbacks && op->callbacks->process_response_event) { /*handle authorization*/ switch (response_code) { case 200: @@ -365,7 +365,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even /*not an auth request*/ op->auth_requests=0; } - op->callbacks.process_response_event(op,event); + op->callbacks->process_response_event(op,event); } else { ms_error("Unhandled event response [%p]",event); } @@ -375,8 +375,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - if (op && op->callbacks.process_timeout) { - op->callbacks.process_timeout(op,event); + if (op && op->callbacks && op->callbacks->process_timeout) { + op->callbacks->process_timeout(op,event); } else { ms_error("Unhandled event timeout [%p]",event); } @@ -393,8 +393,8 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans trans=BELLE_SIP_TRANSACTION(server_transaction); op = (SalOp*)belle_sip_transaction_get_application_data(trans); - if (op && op->callbacks.process_transaction_terminated) { - op->callbacks.process_transaction_terminated(op,event); + if (op && op->callbacks && op->callbacks->process_transaction_terminated) { + op->callbacks->process_transaction_terminated(op,event); } else { ms_message("Unhandled transaction terminated [%p]",trans); } @@ -443,6 +443,7 @@ Sal * sal_init(){ sal->refresher_retry_after=60000; /*default value in ms*/ return sal; } + void sal_set_user_pointer(Sal *sal, void *user_data){ sal->up=user_data; } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 1a38ce7dc..c203c9cb1 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -76,7 +76,8 @@ const char* sal_op_type_to_string(SalOpType type); struct SalOp{ SalOpBase base; - belle_sip_listener_callbacks_t callbacks; + const belle_sip_listener_callbacks_t *callbacks; + SalErrorInfo error_info; belle_sip_client_transaction_t *pending_auth_transaction; belle_sip_server_transaction_t* pending_server_trans; belle_sip_server_transaction_t* pending_update_server_trans; @@ -132,8 +133,10 @@ bool_t sal_op_is_secure(const SalOp* op); void sal_process_authentication(SalOp *op); belle_sip_header_contact_t* sal_op_create_contact(SalOp *op) ; -bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size); -void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ; +bool_t _sal_compute_sal_errors(belle_sip_response_t* response, SalReason* sal_reason, char* reason, size_t reason_size); +SalReason _sal_reason_from_sip_code(int code); + +void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response); /*presence*/ void sal_op_presence_fill_cbs(SalOp*op); /*messaging*/ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 01422e224..a77acafd0 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -38,19 +38,8 @@ static void call_set_released_and_unref(SalOp* op) { static void call_set_error(SalOp* op,belle_sip_response_t* response){ - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; - belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); - char* reason=(char*)belle_sip_response_get_reason_phrase(response); - int code = belle_sip_response_get_status_code(response); - if (reason_header){ - reason = ms_strdup_printf("%s %s",reason,belle_sip_header_get_unparsed_value(reason_header)); - } - sal_compute_sal_errors_from_code(code,&error,&sr); - op->base.root->callbacks.call_failure(op,error,sr,reason,code); - if (reason_header != NULL){ - ms_free(reason); - } + sal_op_set_error_info_from_response(op,response); + op->base.root->callbacks.call_failure(op); } static void sdp_process(SalOp *h){ @@ -127,7 +116,8 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event if (!op->dialog) { /*call terminated very early*/ - op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503); + sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO error",NULL); + op->base.root->callbacks.call_failure(op); call_set_released(op); } else { /*dialog will terminated shortly, nothing to do*/ @@ -290,7 +280,8 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t if (!op->dialog) { /*call terminated very early*/ - op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408); + sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL); + op->base.root->callbacks.call_failure(op); call_set_released(op); } else { /*dialog will terminated shortly, nothing to do*/ @@ -631,13 +622,18 @@ int sal_call(SalOp *op, const char *from, const char *to){ return sal_op_send_request(op,invite); } +static belle_sip_listener_callbacks_t call_op_callbacks={0}; + void sal_op_call_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=call_process_io_error; - op->callbacks.process_response_event=call_process_response; - op->callbacks.process_timeout=call_process_timeout; - op->callbacks.process_transaction_terminated=call_process_transaction_terminated; - op->callbacks.process_request_event=process_request_event; - op->callbacks.process_dialog_terminated=process_dialog_terminated; + if (call_op_callbacks.process_response_event==NULL){ + call_op_callbacks.process_io_error=call_process_io_error; + call_op_callbacks.process_response_event=call_process_response; + call_op_callbacks.process_timeout=call_process_timeout; + call_op_callbacks.process_transaction_terminated=call_process_transaction_terminated; + call_op_callbacks.process_request_event=process_request_event; + call_op_callbacks.process_dialog_terminated=process_dialog_terminated; + } + op->callbacks=&call_op_callbacks; op->type=SalOpCall; } diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 1972c97f6..4409c73a3 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -37,8 +37,6 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher ,unsigned int status_code ,const char* reason_phrase) { SalOp* op = (SalOp*)user_pointer; - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; belle_sip_transaction_t *tr=BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)); /*belle_sip_response_t* response=belle_sip_transaction_get_response(tr);*/ SalSubscribeStatus sss=SalSubscribeTerminated; @@ -50,8 +48,8 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher set_or_update_dialog(op,belle_sip_transaction_get_dialog(tr)); } if (status_code>=200){ - sal_compute_sal_errors_from_code(status_code,&error,&sr); - op->base.root->callbacks.subscribe_response(op,sss,error,sr); + sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + op->base.root->callbacks.subscribe_response(op,sss); }else if (status_code==0){ op->base.root->callbacks.on_expire(op); } @@ -172,13 +170,18 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque } } +static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 }; + void sal_op_subscribe_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=subscribe_process_io_error; - op->callbacks.process_response_event=subscribe_response_event; - op->callbacks.process_timeout=subscribe_process_timeout; - op->callbacks.process_transaction_terminated=subscribe_process_transaction_terminated; - op->callbacks.process_request_event=subscribe_process_request_event; - op->callbacks.process_dialog_terminated=subscribe_process_dialog_terminated; + if (op_subscribe_callbacks.process_io_error==NULL){ + op_subscribe_callbacks.process_io_error=subscribe_process_io_error; + op_subscribe_callbacks.process_response_event=subscribe_response_event; + op_subscribe_callbacks.process_timeout=subscribe_process_timeout; + op_subscribe_callbacks.process_transaction_terminated=subscribe_process_transaction_terminated; + op_subscribe_callbacks.process_request_event=subscribe_process_request_event; + op_subscribe_callbacks.process_dialog_terminated=subscribe_process_dialog_terminated; + } + op->callbacks=&op_subscribe_callbacks; op->type=SalOpSubscribe; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index b3124300c..3e5ebe2a5 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -62,6 +62,7 @@ void sal_op_release_impl(SalOp *op){ if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans); if (op->event) belle_sip_object_unref(op->event); + sal_error_info_reset(&op->error_info); __sal_op_free(op); return ; } @@ -334,6 +335,12 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { SalReason sal_reason_to_sip_code(SalReason r){ int ret=500; switch(r){ + case SalReasonNone: + ret=200; + break; + case SalReasonIOError: + ret=503; + break; case SalReasonUnknown: ret=400; break; @@ -401,110 +408,123 @@ SalReason sal_reason_to_sip_code(SalReason r){ return ret; } -void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { - *sal_err=SalErrorFailure; +SalReason _sal_reason_from_sip_code(int code) { + if (code>=100 && code<300) return SalReasonNone; + switch(code) { + case 0: + return SalReasonIOError; case 301: - *sal_reason=SalReasonMovedPermanently; - break; + return SalReasonMovedPermanently; case 302: - *sal_reason=SalReasonRedirect; - break; + return SalReasonRedirect; case 401: case 407: - *sal_reason=SalReasonUnauthorized; - break; + return SalReasonUnauthorized; case 403: - *sal_reason=SalReasonForbidden; - break; + return SalReasonForbidden; case 404: - *sal_reason=SalReasonNotFound; - break; + return SalReasonNotFound; case 408: - *sal_reason=SalReasonRequestTimeout; - break; + return SalReasonRequestTimeout; case 410: - *sal_reason=SalReasonGone; - break; + return SalReasonGone; case 415: - *sal_reason=SalReasonUnsupportedContent; - break; + return SalReasonUnsupportedContent; case 422: ms_error ("422 not implemented yet");; break; case 480: - *sal_reason=SalReasonTemporarilyUnavailable; - break; + return SalReasonTemporarilyUnavailable; case 481: - *sal_reason=SalReasonNoMatch; - break; + return SalReasonNoMatch; case 484: - *sal_reason=SalReasonAddressIncomplete; - break; + return SalReasonAddressIncomplete; case 486: - *sal_reason=SalReasonBusy; - break; + return SalReasonBusy; case 487: - break; + return SalReasonNone; case 488: - *sal_reason=SalReasonNotAcceptable; - break; + return SalReasonNotAcceptable; case 491: - *sal_reason=SalReasonRequestPending; - break; + return SalReasonRequestPending; case 501: - *sal_reason=SalReasonNotImplemented; - break; + return SalReasonNotImplemented; case 502: - *sal_reason=SalReasonBadGateway; - break; + return SalReasonBadGateway; case 504: - *sal_reason=SalReasonServerTimeout; - break; + return SalReasonServerTimeout; case 600: - *sal_reason=SalReasonDoNotDisturb; - break; + return SalReasonDoNotDisturb; case 603: - *sal_reason=SalReasonDeclined; - break; + return SalReasonDeclined; case 503: - *sal_reason=SalReasonServiceUnavailable; - break; + return SalReasonServiceUnavailable; default: - if (code>=300){ - *sal_err=SalErrorFailure; - *sal_reason=SalReasonUnknown; - }else if (code>=100){ - *sal_err=SalErrorNone; - *sal_reason=SalReasonUnknown; - }else if (code==0){ - *sal_err=SalErrorNoResponse; - } - /* no break */ + return SalReasonUnknown; + } + return SalReasonUnknown; +} + +const SalErrorInfo *sal_error_info_none(void){ + static SalErrorInfo none={ + SalReasonNone, + "Ok", + 200, + NULL, + NULL + }; + return &none; +} + +void sal_error_info_reset(SalErrorInfo *ei){ + if (ei->status_string){ + ms_free(ei->status_string); + ei->status_string=NULL; + } + if (ei->warnings){ + ms_free(ei->warnings); + ei->warnings=NULL; + + } + if (ei->full_string){ + ms_free(ei->full_string); + ei->full_string=NULL; + } + ei->protocol_code=0; + ei->reason=SalReasonNone; +} + +void sal_error_info_set(SalErrorInfo *ei, SalReason reason, int code, const char *status_string, const char *warning){ + sal_error_info_reset(ei); + if (reason==SalReasonUnknown) ei->reason=_sal_reason_from_sip_code(code); + else ei->reason=reason; + ei->protocol_code=code; + ei->status_string=status_string ? ms_strdup(status_string) : NULL; + ei->warnings=warning ? ms_strdup(warning) : NULL; + if (ei->status_string){ + if (ei->warnings) + ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings); + else ei->full_string=ms_strdup(ei->status_string); } } -/*return TRUE if error code*/ -bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) { - int code = belle_sip_response_get_status_code(response); - belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); - *sal_err=SalErrorUnknown; - *sal_reason = SalReasonUnknown; - if (reason_header){ - snprintf(reason - ,reason_size - ,"%s %s" - ,belle_sip_response_get_reason_phrase(response) - ,belle_sip_header_get_unparsed_value(reason_header)); - } else { - strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size); - } - if (code>=400) { - sal_compute_sal_errors_from_code(code,sal_err,sal_reason); - return TRUE; - } else { - return FALSE; - } +void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response){ + int code = belle_sip_response_get_status_code(response); + const char *reason_phrase=belle_sip_response_get_reason_phrase(response); + /*Remark: the reason header is to be used mainly in SIP requests, thus the use and prototype of this function should be changed.*/ + belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); + belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning"); + SalErrorInfo *ei=&op->error_info; + const char *warnings; + + warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL; + if (warnings==NULL) warnings=reason_header ? belle_sip_header_get_unparsed_value(reason_header) : NULL; + sal_error_info_set(ei,SalReasonUnknown,code,reason_phrase,warnings); +} + +const SalErrorInfo *sal_op_get_error_info(const SalOp *op){ + return &op->error_info; } void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index bf7f7b82a..05f1199b8 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void process_error( SalOp* op) { if (op->dir == SalOpDirOutgoing) { - op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed, SalReasonUnknown); + op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed); } else { ms_warning("unexpected io error for incoming message on op [%p]",op); } @@ -30,33 +30,20 @@ static void process_error( SalOp* op) { static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ SalOp* op = (SalOp*)user_ctx; -// belle_sip_object_t* source = belle_sip_io_error_event_get_source(event); -// if (BELLE_SIP_IS_INSTANCE_OF(source,belle_sip_transaction_t)) { -// /*reset op to make sure transaction terminated does not need op*/ -// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(source),NULL); -// } + sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO Error",NULL); process_error(op); } static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { SalOp* op=(SalOp*)user_ctx; -// belle_sip_client_transaction_t *client_transaction=belle_sip_timeout_event_get_client_transaction(event); -// belle_sip_server_transaction_t *server_transaction=belle_sip_timeout_event_get_server_transaction(event); -// /*reset op to make sure transaction terminated does not need op*/ -// if (client_transaction) { -// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL); -// } else { -// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),NULL); -// } + sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL); process_error(op); } static void process_response_event(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; - /*belle_sip_client_transaction_t *client_transaction=belle_sip_response_event_get_client_transaction(event);*/ int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); SalTextDeliveryStatus status; - SalReason reason=SalReasonUnknown; - SalError err=SalErrorNone; + sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); if (code>=100 && code <200) status=SalTextDeliveryInProgress; @@ -64,13 +51,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);*/ - } - sal_compute_sal_errors_from_code(code,&err,&reason); - op->base.root->callbacks.text_delivery_update(op,status, reason); + + 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; @@ -191,10 +175,15 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) return sal_message_send(op,from,to,"text/plain",msg); } +static belle_sip_listener_callbacks_t op_message_callbacks={0}; + void sal_op_message_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=process_io_error; - op->callbacks.process_response_event=process_response_event; - op->callbacks.process_timeout=process_timeout; - op->callbacks.process_request_event=process_request_event; + if (op_message_callbacks.process_io_error==NULL){ + op_message_callbacks.process_io_error=process_io_error; + op_message_callbacks.process_response_event=process_response_event; + op_message_callbacks.process_timeout=process_timeout; + op_message_callbacks.process_request_event=process_request_event; + } + op->callbacks=&op_message_callbacks; op->type=SalOpMessage; } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 9f7d6f871..ca526fd5d 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -94,13 +94,12 @@ static void presence_response_event(void *op_base, const belle_sip_response_even belle_sip_response_t* response=belle_sip_response_event_get_response(event); belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); int code = belle_sip_response_get_status_code(response); - char reason[256]={0}; - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; belle_sip_header_expires_t* expires; + + sal_op_set_error_info_from_response(op,response); - if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) { - ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); + if (code>=300) { + ms_message("subscription to [%s] rejected",sal_op_get_to(op)); op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ return; } @@ -267,13 +266,18 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques } } +static belle_sip_listener_callbacks_t op_presence_callbacks={0}; + void sal_op_presence_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=presence_process_io_error; - op->callbacks.process_response_event=presence_response_event; - op->callbacks.process_timeout=presence_process_timeout; - op->callbacks.process_transaction_terminated=presence_process_transaction_terminated; - op->callbacks.process_request_event=presence_process_request_event; - op->callbacks.process_dialog_terminated=presence_process_dialog_terminated; + if (op_presence_callbacks.process_request_event==NULL){ + op_presence_callbacks.process_io_error=presence_process_io_error; + op_presence_callbacks.process_response_event=presence_response_event; + op_presence_callbacks.process_timeout=presence_process_timeout; + op_presence_callbacks.process_transaction_terminated=presence_process_transaction_terminated; + op_presence_callbacks.process_request_event=presence_process_request_event; + op_presence_callbacks.process_dialog_terminated=presence_process_dialog_terminated; + } + op->callbacks=&op_presence_callbacks; op->type=SalOpPresence; } diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index a55042919..81a7ce724 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -35,24 +35,26 @@ static void publish_refresher_listener (belle_sip_refresher_t* refresher }else if (status_code==0){ op->base.root->callbacks.on_expire(op); }else if (status_code>=200){ - SalError err; - SalReason reason; - sal_compute_sal_errors_from_code(status_code,&err,&reason); - op->base.root->callbacks.on_publish_response(op,err,reason); + sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + op->base.root->callbacks.on_publish_response(op); } } static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){ SalOp *op=(SalOp*)userctx; - int code=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); - SalError err; - SalReason reason; - sal_compute_sal_errors_from_code(code,&err,&reason); - op->base.root->callbacks.on_publish_response(op,err,reason); + sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); + if (op->error_info.protocol_code>=200){ + op->base.root->callbacks.on_publish_response(op); + } } -void sal_op_publish_fill_cbs(SalOp*op) { - op->callbacks.process_response_event=publish_response_event; +static belle_sip_listener_callbacks_t op_publish_callbacks={0}; + +void sal_op_publish_fill_cbs(SalOp *op) { + if (op_publish_callbacks.process_response_event==NULL){ + op_publish_callbacks.process_response_event=publish_response_event; + } + op->callbacks=&op_publish_callbacks; op->type=SalOpPublish; } diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 2f12d4533..17a3861b4 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -24,8 +24,6 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher ,unsigned int status_code ,const char* reason_phrase) { SalOp* op = (SalOp*)user_pointer; - SalError sal_err; - SalReason sal_reason; belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher))); ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); @@ -57,9 +55,8 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher chooses not to re-register, the UA SHOULD discard any stored service route for that address-of-record. */ sal_op_set_service_route(op,NULL); - - sal_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason); - op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); + sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + op->base.root->callbacks.register_failure(op); if (op->auth_info) { /*add pending auth*/ sal_add_pending_auth(op->base.root,op); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 469baf8af..80818be37 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif -static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); +static void register_failure(SalOp *op); static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED; @@ -550,7 +550,7 @@ static void call_terminated(SalOp *op, const char *from){ break; case LinphoneCallIncomingReceived: case LinphoneCallIncomingEarlyMedia: - call->reason=LinphoneReasonNotAnswered; + sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,0,"Incoming call cancelled",NULL); break; default: break; @@ -593,14 +593,15 @@ static int resume_call_after_failed_transfer(LinphoneCall *call){ return BELLE_SIP_STOP; } -static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){ +static void call_failure(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + const SalErrorInfo *ei=sal_op_get_error_info(op); char *msg486=_("User is busy."); char *msg480=_("User is temporarily unavailable."); /*char *retrymsg=_("%s. Retry after %i minute(s).");*/ char *msg600=_("User does not want to be disturbed."); char *msg603=_("Call declined."); - const char *msg=details; + const char *msg=ei->full_string; LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); LinphoneCall *referer=call->referer; @@ -610,102 +611,95 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } if (lc->vtable.show) lc->vtable.show(lc); - - if (error==SalErrorNoResponse){ - msg=_("No response."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - }else if (error==SalErrorProtocol){ - msg=details ? details : _("Protocol error."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc, msg); - }else if (error==SalErrorFailure){ - switch(sr){ - case SalReasonDeclined: - msg=msg603; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg603); - break; - case SalReasonBusy: - msg=msg486; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg486); - break; - case SalReasonRedirect: - { - ms_error("case SalReasonRedirect"); + switch(ei->reason){ + case SalReasonNone: + break; + case SalReasonRequestTimeout: + msg=_("Request timeout."); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + break; + case SalReasonDeclined: + msg=msg603; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg603); + break; + case SalReasonBusy: + msg=msg486; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg486); + break; + case SalReasonRedirect: + { + linphone_call_stop_media_streams(call); + if ( call->state==LinphoneCallOutgoingInit + || call->state==LinphoneCallOutgoingProgress + || call->state==LinphoneCallOutgoingRinging /*push case*/ + || call->state==LinphoneCallOutgoingEarlyMedia){ + LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op); + if( redirection_to ){ + char* url = linphone_address_as_string(redirection_to); + ms_warning("Redirecting call [%p] to %s",call, url); + ms_free(url); + linphone_call_create_op(call); + linphone_core_start_invite(lc, call, redirection_to); + return; + } + } + msg=_("Redirected"); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + } + break; + case SalReasonTemporarilyUnavailable: + msg=msg480; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg480); + break; + case SalReasonNotFound: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + break; + case SalReasonDoNotDisturb: + msg=msg600; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg600); + break; + case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP && + !linphone_core_is_media_encryption_mandatory(lc)) { + int i; + ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call); linphone_call_stop_media_streams(call); - if ( call->state==LinphoneCallOutgoingInit + if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress || call->state==LinphoneCallOutgoingRinging /*push case*/ || call->state==LinphoneCallOutgoingEarlyMedia){ - LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op); - if( redirection_to ){ - char* url = linphone_address_as_string(redirection_to); - ms_error("Redirecting call [%p] to %s",call, url); - ms_free(url); - linphone_call_create_op(call); - linphone_core_start_invite(lc, call, redirection_to); - return; + ms_message("Retrying call [%p] with AVP",call); + /* clear SRTP local params */ + call->params.media_encryption = LinphoneMediaEncryptionNone; + for(i=0; ilocaldesc->n_active_streams; i++) { + call->localdesc->streams[i].proto = SalProtoRtpAvp; + memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); } + linphone_core_restart_invite(lc, call); + return; } - msg=_("Redirected"); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); } - break; - case SalReasonTemporarilyUnavailable: - msg=msg480; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg480); - break; - case SalReasonNotFound: - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - break; - case SalReasonDoNotDisturb: - msg=msg600; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg600); - break; - case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP && - !linphone_core_is_media_encryption_mandatory(lc)) { - int i; - ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call); - linphone_call_stop_media_streams(call); - if ( call->state==LinphoneCallOutgoingInit - || call->state==LinphoneCallOutgoingProgress - || call->state==LinphoneCallOutgoingRinging /*push case*/ - || call->state==LinphoneCallOutgoingEarlyMedia){ - ms_message("Retrying call [%p] with AVP",call); - /* clear SRTP local params */ - call->params.media_encryption = LinphoneMediaEncryptionNone; - for(i=0; ilocaldesc->n_active_streams; i++) { - call->localdesc->streams[i].proto = SalProtoRtpAvp; - memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); - } - linphone_core_restart_invite(lc, call); - return; - } - - } - msg=_("Incompatible media parameters."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - break; - case SalReasonRequestPending: - /*restore previous state, the application will decide to resubmit the action if relevant*/ - call->reason=linphone_reason_from_sal(sr); - linphone_call_set_state(call,call->prevstate,msg); - return; - break; - default: - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Call failed.")); - } + msg=_("Incompatible media parameters."); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + break; + case SalReasonRequestPending: + /*restore previous state, the application will decide to resubmit the action if relevant*/ + linphone_call_set_state(call,call->prevstate,msg); + return; + break; + default: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Call failed.")); } /*some call error are not fatal*/ @@ -714,8 +708,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de case LinphoneCallPausing: case LinphoneCallResuming: ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate)); - call->reason=linphone_reason_from_sal(sr); - linphone_call_set_state(call, call->prevstate,details); + linphone_call_set_state(call, call->prevstate,ei->full_string); return; default: break; /*nothing to do*/ @@ -728,13 +721,14 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de linphone_call_delete_upnp_session(call); #endif //BUILD_UPNP - call->reason=linphone_reason_from_sal(sr); - if (sr==SalReasonDeclined){ - linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); - }else{ - linphone_call_set_state(call,LinphoneCallError,details); + if (call->state!=LinphoneCallEnd && call->state!=LinphoneCallError){ + if (ei->reason==SalReasonDeclined){ + linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); + }else{ + linphone_call_set_state(call,LinphoneCallError,ei->full_string); + } + if (ei->reason!=SalReasonNone) linphone_core_play_call_error_tone(lc,linphone_reason_from_sal(ei->reason)); } - linphone_core_play_call_error_tone(lc,call->reason); if (referer){ /*notify referer of the failure*/ @@ -773,7 +767,6 @@ static void register_success(SalOp *op, bool_t registered){ ms_message("Registration success for removed proxy config, ignored"); return; } - linphone_proxy_config_set_error(cfg,LinphoneReasonNone); linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared , registered ? "Registration successful" : "Unregistration done"); if (lc->vtable.display_status){ @@ -785,9 +778,11 @@ static void register_success(SalOp *op, bool_t registered){ } -static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){ +static void register_failure(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); + const SalErrorInfo *ei=sal_op_get_error_info(op); + const char *details=ei->full_string; if (cfg==NULL){ ms_warning("Registration failed for unknown proxy config."); @@ -801,15 +796,12 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const details=_("no response timeout"); if (lc->vtable.display_status) { - char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details ); + char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op), details); lc->vtable.display_status(lc,msg); ms_free(msg); } - linphone_proxy_config_set_error(cfg,linphone_reason_from_sal(reason)); - - if (error== SalErrorFailure - && reason == SalReasonServiceUnavailable + if ((ei->reason == SalReasonServiceUnavailable || ei->reason == SalReasonIOError) && linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) { linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying")); } else { @@ -1031,22 +1023,15 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus sta return LinphoneChatMessageStateIdle; } -static int op_equals(LinphoneCall *a, SalOp *b) { - return a->op !=b; /*return 0 if equals*/ -} - -static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status, SalReason reason){ +static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); - const MSList* calls; if (chat_msg == NULL) { // Do not handle delivery status for isComposing messages. return; } - calls = linphone_core_get_calls(chat_msg->chat_room->lc); chat_msg->state=chatStatusSal2Linphone(status); - chat_msg->reason=linphone_reason_from_sal(reason); linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { ms_message("Notifying text delivery with status %i",chat_msg->state); @@ -1056,11 +1041,6 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status, SalRea } 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); - } } } @@ -1069,7 +1049,7 @@ static void info_received(SalOp *op, const SalBody *body){ linphone_core_notify_info_message(lc,op,body); } -static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason){ +static void subscribe_response(SalOp *op, SalSubscribeStatus status){ LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); if (lev==NULL) return; @@ -1079,7 +1059,6 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError er }else if (status==SalSubscribePending){ linphone_event_set_state(lev,LinphoneSubscriptionPending); }else{ - linphone_event_set_reason(lev, linphone_reason_from_sal(reason)); linphone_event_set_state(lev,LinphoneSubscriptionError); } } @@ -1121,18 +1100,18 @@ static void subscribe_closed(SalOp *op){ linphone_event_set_state(lev,LinphoneSubscriptionTerminated); } -static void on_publish_response(SalOp* op, SalError err, SalReason reason){ +static void on_publish_response(SalOp* op){ LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + const SalErrorInfo *ei=sal_op_get_error_info(op); if (lev==NULL) return; - if (err==SalErrorNone){ + if (ei->reason==SalReasonNone){ if (!lev->terminating) linphone_event_set_publish_state(lev,LinphonePublishOk); else linphone_event_set_publish_state(lev,LinphonePublishCleared); }else{ - linphone_event_set_reason(lev,linphone_reason_from_sal(reason)); linphone_event_set_publish_state(lev,LinphonePublishError); } } diff --git a/coreapi/chat.c b/coreapi/chat.c index bb944e1cc..264d6d768 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -160,7 +160,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM identity=linphone_proxy_config_get_identity(proxy); }else identity=linphone_core_get_primary_contact(cr->lc); /*sending out of calls*/ - op = sal_op_new(cr->lc->sal); + msg->op = op = sal_op_new(cr->lc->sal); linphone_configure_op(cr->lc,op,cr->peer_url,msg->custom_headers,lp_config_get_int(cr->lc->config,"sip","chat_msg_with_contact",0)); sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/ } @@ -779,6 +779,7 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) * Destroys a LinphoneChatMessage. **/ void linphone_chat_message_destroy(LinphoneChatMessage* msg) { + if (msg->op) sal_op_release(msg->op); if (msg->message) ms_free(msg->message); if (msg->external_body_url) ms_free(msg->external_body_url); if (msg->from) linphone_address_destroy(msg->from); @@ -787,9 +788,17 @@ void linphone_chat_message_destroy(LinphoneChatMessage* msg) { ms_free(msg); } +/** + * Get full details about delivery error of a chat message. + * @param msg a LinphoneChatMessage + * @return a LinphoneErrorInfo describing the details. +**/ +const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg){ + return linphone_error_info_from_sal_op(msg->op); +} LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) { - return msg->reason; + return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); } /** diff --git a/coreapi/event.c b/coreapi/event.c index 6a7930943..e4d66db3e 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -114,12 +114,12 @@ LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){ return lev->publish_state; } -void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason){ - lev->reason=reason; +const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev){ + return linphone_error_info_from_sal_op(lev->op); } LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ - return lev->reason; + return linphone_error_info_get_reason(linphone_event_get_error_info(lev)); } LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){ diff --git a/coreapi/event.h b/coreapi/event.h index e01ab9414..5985d1c96 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -207,6 +207,11 @@ LINPHONE_PUBLIC int linphone_event_update_publish(LinphoneEvent *lev, const Linp **/ LINPHONE_PUBLIC LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev); +/** + * Get full details about an error occured. +**/ +const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev); + /** * Get subscription state. If the event object was not created by a subscription mechanism, #LinphoneSubscriptionNone is returned. **/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d5c0bdf3c..4ff3537fb 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -793,11 +793,11 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const call->state=cstate; } if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){ - switch(call->reason){ - case LinphoneReasonDeclined: + switch(call->non_op_error.reason){ + case SalReasonDeclined: call->log->status=LinphoneCallDeclined; break; - case LinphoneReasonNotAnswered: + case SalReasonRequestTimeout: call->log->status=LinphoneCallMissed; break; default: @@ -814,6 +814,11 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const lc->vtable.call_state_changed(lc,call,cstate,message); if (cstate==LinphoneCallReleased){ if (call->op!=NULL) { + /*transfer the last error so that it can be obtained even in Released state*/ + if (call->non_op_error.reason==SalReasonNone){ + const SalErrorInfo *ei=sal_op_get_error_info(call->op); + sal_error_info_set(&call->non_op_error,ei->reason,ei->protocol_code,ei->status_string,ei->warnings); + } /* so that we cannot have anymore upcalls for SAL concerning this call*/ sal_op_release(call->op); @@ -877,6 +882,7 @@ static void linphone_call_destroy(LinphoneCall *obj) } linphone_call_params_uninit(&obj->params); linphone_call_params_uninit(&obj->current_params); + sal_error_info_reset(&obj->non_op_error); ms_free(obj); } @@ -998,7 +1004,16 @@ LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ * Returns the reason for a call termination (either error or normal termination) **/ LinphoneReason linphone_call_get_reason(const LinphoneCall *call){ - return call->reason; + return linphone_error_info_get_reason(linphone_call_get_error_info(call)); +} + +/** + * Returns full details about call errors or termination reasons. +**/ +const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call){ + if (call->non_op_error.reason!=SalReasonNone){ + return (const LinphoneErrorInfo*)&call->non_op_error; + }else return linphone_error_info_from_sal_op(call->op); } /** diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 38093e7c8..9cd36d0fd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2281,7 +2281,7 @@ void linphone_core_iterate(LinphoneCore *lc){ ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); decline_reason=lc->current_call ? LinphoneReasonBusy : LinphoneReasonDeclined; call->log->status=LinphoneCallMissed; - call->reason=LinphoneReasonNotAnswered; + sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,408,"Not answered",NULL); linphone_core_decline_call(lc,call,decline_reason); } } @@ -3470,8 +3470,8 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ if (call->state==LinphoneCallIncomingReceived){ - if (call->reason!=LinphoneReasonNotAnswered) - call->reason=LinphoneReasonDeclined; + if (call->non_op_error.reason!=SalReasonRequestTimeout) + call->non_op_error.reason=SalReasonDeclined; } /*stop ringing*/ linphone_core_stop_ringing(lc); @@ -3490,7 +3490,7 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri){ if (call->state==LinphoneCallIncomingReceived){ sal_call_decline(call->op,SalReasonRedirect,redirect_uri); - call->reason=LinphoneReasonDeclined; + sal_error_info_set(&call->non_op_error,SalReasonRedirect,603,"Call redirected",NULL); terminate_call(lc,call); }else{ ms_error("Bad state for call redirection."); @@ -6152,6 +6152,8 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "Bad gateway"; case LinphoneReasonServerTimeout: return "Server timeout"; + case LinphoneReasonUnknown: + return "Unknown error"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2af2d54de..f2d4b2514 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -159,6 +159,7 @@ typedef struct _LinphoneCall LinphoneCall; * Enum describing various failure reasons or contextual information for some events. * @see linphone_call_get_reason() * @see linphone_proxy_config_get_error() + * @see linphone_error_info_get_reason() * @ingroup misc **/ enum _LinphoneReason{ @@ -181,7 +182,8 @@ enum _LinphoneReason{ LinphoneReasonAddressIncomplete, /**
reason); +} + +/** + * Get textual phrase from the error info. + * This is the text that is provided by the peer in the protocol (SIP). + * @param ei the error info. + * @return the error phrase + * @ingroup misc +**/ +const char *linphone_error_info_get_phrase(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->status_string; +} + +/** + * Provides additional information regarding the failure. + * With SIP protocol, the "Reason" and "Warning" headers are returned. + * @param ei the error info. + * @return more details about the failure. + * @ingroup misc +**/ +const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->warnings; +} + +/** + * Get the status code from the low level protocol (ex a SIP status code). + * @param ei the error info. + * @return the status code. + * @ingroup misc +**/ +int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->protocol_code; +} + /** * Set the name of the mediastreamer2 filter to be used for rendering video. * This is for advanced users of the library, mainly to workaround hardware/driver bugs. diff --git a/coreapi/private.h b/coreapi/private.h index 9e8d0af0f..18de67587 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -146,7 +146,7 @@ struct _LinphoneChatMessage { LinphoneChatMessageState state; bool_t is_read; unsigned int storage_id; - LinphoneReason reason; + SalOp *op; }; typedef struct StunCandidate{ @@ -159,6 +159,7 @@ struct _LinphoneCall { int magic; /*used to distinguish from proxy config*/ struct _LinphoneCore *core; + SalErrorInfo non_op_error; int af; /*the address family to prefer for RTP path, guessed from signaling path*/ LinphoneCallDir dir; SalMediaDescription *biggestdesc; /*media description with all already proposed streams, used to remember the mapping of streams*/ @@ -174,7 +175,6 @@ struct _LinphoneCall LinphoneCallState state; LinphoneCallState prevstate; LinphoneCallState transfer_state; /*idle if no transfer*/ - LinphoneReason reason; LinphoneProxyConfig *dest_proxy; int refcnt; void * user_pointer; @@ -204,7 +204,7 @@ struct _LinphoneCall unsigned int remote_session_ver; LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ - int localdesc_changed; + int localdesc_changed;/*not a boolean, contains a mask representing changes*/ bool_t refer_pending; bool_t expect_media_in_ack; @@ -373,7 +373,6 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); extern SalCallbacks linphone_sal_callbacks; -void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error); bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LinphoneCall * is_a_linphone_call(void *user_pointer); @@ -413,7 +412,6 @@ struct _LinphoneProxyConfig bool_t pad[3]; void* user_data; time_t deletion_date; - LinphoneReason error; LinphonePrivacyMask privacy; }; @@ -693,7 +691,6 @@ struct _LinphoneEvent{ SalCustomHeader *send_custom_headers; LinphoneSubscriptionState subscription_state; LinphonePublishState publish_state; - LinphoneReason reason; void *userdata; int refcnt; char *name; @@ -806,7 +803,6 @@ LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name); void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state); -void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason); LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); @@ -847,6 +843,10 @@ char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char * void linphone_free_xml_text_content(const char *text); xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +static inline const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){ + if (op==NULL) return (LinphoneErrorInfo*)sal_error_info_none(); + return (const LinphoneErrorInfo*)sal_op_get_error_info(op); +} /** Belle Sip-based objects need unique ids */ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 5e0b8ff18..74c8a7730 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1368,11 +1368,11 @@ LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyCon } LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) { - return cfg->error; + return linphone_error_info_get_reason(linphone_proxy_config_get_error_info(cfg)); } -void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason error) { - cfg->error = error; +const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProxyConfig *cfg){ + return linphone_error_info_from_sal_op(cfg->op); } const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) { diff --git a/include/sal/sal.h b/include/sal/sal.h index 650b5085a..f508484ec 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -254,6 +254,7 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type); void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir); + /*this structure must be at the first byte of the SalOp structure defined by implementors*/ typedef struct SalOpBase{ Sal *root; @@ -279,15 +280,8 @@ typedef struct SalOpBase{ } SalOpBase; -typedef enum SalError{ - SalErrorNone, - SalErrorNoResponse, - SalErrorProtocol, - SalErrorFailure, /* see SalReason for more details */ - SalErrorUnknown -} SalError; - typedef enum SalReason{ + SalReasonNone, /*no error, please leave first so that it takes 0 value*/ SalReasonDeclined, SalReasonBusy, SalReasonRedirect, @@ -308,11 +302,20 @@ typedef enum SalReason{ SalReasonAddressIncomplete, SalReasonNotImplemented, SalReasonBadGateway, - SalReasonServerTimeout + SalReasonServerTimeout, + SalReasonIOError }SalReason; const char* sal_reason_to_string(const SalReason reason); +typedef struct SalErrorInfo{ + SalReason reason; + char *status_string; + int protocol_code; + char *warnings; + char *full_string; /*concatenation of status_string + warnings*/ +}SalErrorInfo; + typedef enum SalPresenceStatus{ SalPresenceOffline, SalPresenceOnline, @@ -400,21 +403,21 @@ typedef void (*SalOnCallAccepted)(SalOp *op); typedef void (*SalOnCallAck)(SalOp *op); typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE/UPDATE is received*/ typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); -typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code); +typedef void (*SalOnCallFailure)(SalOp *op); typedef void (*SalOnCallReleased)(SalOp *salop); typedef void (*SalOnAuthRequestedLegacy)(SalOp *op, const char *realm, const char *username); typedef bool_t (*SalOnAuthRequested)(Sal *sal,SalAuthInfo* info); typedef void (*SalOnAuthFailure)(SalOp *op, SalAuthInfo* info); typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); -typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details); +typedef void (*SalOnRegisterFailure)(SalOp *op); typedef void (*SalOnVfuRequest)(SalOp *op); 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, SalReason); +typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus); typedef void (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); -typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason); +typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status); 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); @@ -425,7 +428,7 @@ typedef void (*SalOnSubscribePresenceReceived)(SalOp *salop, const char *from); typedef void (*SalOnSubscribePresenceClosed)(SalOp *salop, const char *from); typedef void (*SalOnPingReply)(SalOp *salop); typedef void (*SalOnInfoReceived)(SalOp *salop, const SalBody *body); -typedef void (*SalOnPublishResponse)(SalOp *salop, SalError error, SalReason reason); +typedef void (*SalOnPublishResponse)(SalOp *salop); typedef void (*SalOnExpire)(SalOp *salop); /*allows sal implementation to access auth info if available, return TRUE if found*/ @@ -577,6 +580,11 @@ bool_t sal_op_is_ipv6(SalOp *op); /*returns TRUE if there is no pending request that may block a future one */ bool_t sal_op_is_idle(SalOp *op); +const SalErrorInfo *sal_error_info_none(void); +const SalErrorInfo *sal_op_get_error_info(const SalOp *op); +void sal_error_info_reset(SalErrorInfo *ei); +void sal_error_info_set(SalErrorInfo *ei, SalReason reason, int code, const char *status_string, const char *warning); + /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); diff --git a/tester/call_tester.c b/tester/call_tester.c index 515c7980e..ed44faa9e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -914,7 +914,7 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); linphone_core_set_play_file(laure->lc,hellopath); if (enable_caller_privacy) - linphone_call_params_set_privacy(laure_params,LinphonePrivacyId); + linphone_call_params_set_privacy(laure_params,LinphonePrivacyId); CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(laure->lc,pauline->identity,laure_params)); @@ -1185,7 +1185,7 @@ static void early_media_call_with_ringing(void){ marie_call = linphone_core_invite_address(marie->lc, pauline->identity); - CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); From c08b540f7b09afc92759207ad39e4ac96e7b3c62 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 21 Mar 2014 19:06:33 +0100 Subject: [PATCH 359/439] fix crash in ms2, enhance audio assistant, fix crash when changing the record device --- gtk/audio_assistant.c | 54 +++++++++++++++++++++++-------------------- gtk/incall_view.c | 4 ++-- mediastreamer2 | 2 +- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/gtk/audio_assistant.c b/gtk/audio_assistant.c index a9ecdd1bb..1e5bbddeb 100644 --- a/gtk/audio_assistant.c +++ b/gtk/audio_assistant.c @@ -25,37 +25,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/msvolume.h" static GtkWidget *audio_assistant=NULL; +static void prepare(GtkAssistant *w); GtkWidget *get_widget_from_assistant(const char *name){ return (GtkWidget *)g_object_get_data(G_OBJECT(audio_assistant),name); } -void set_widget_to_assistant(const char *name,GtkWidget *w){ + +static void set_widget_to_assistant(const char *name,GtkWidget *w){ g_object_set_data(G_OBJECT(audio_assistant),name,w); } -void update_record_button(gboolean is_visible){ +static void update_record_button(gboolean is_visible){ GtkWidget *rec_button = get_widget_from_assistant("rec_button"); gtk_widget_set_sensitive(rec_button,is_visible); } -void activate_record_button(gboolean is_active){ +#if 0 +static void activate_record_button(gboolean is_active){ GtkWidget *rec_button = get_widget_from_assistant("rec_button"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rec_button),is_active); } +#endif -void update_play_button(gboolean is_visible){ +static void update_play_button(gboolean is_visible){ GtkWidget *play_button = get_widget_from_assistant("play_button"); gtk_widget_set_sensitive(play_button,is_visible); } -void activate_play_button(gboolean is_active){ +static void activate_play_button(gboolean is_active){ GtkWidget *play_button = get_widget_from_assistant("play_button"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),is_active); } - - -gchar *get_record_file(){ +static gchar *get_record_file(){ char filename[256]={0}; char date[64]={0}; time_t curtime=time(NULL); @@ -72,7 +74,7 @@ gchar *get_record_file(){ return g_build_path(G_DIR_SEPARATOR_S,g_get_tmp_dir(),filename,NULL);; } -float audio_stream_get_record_volume(AudioStream *st){ +static float audio_stream_get_record_volume(AudioStream *st){ if (st && st->volsend){ float vol=0; ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol); @@ -81,7 +83,7 @@ float audio_stream_get_record_volume(AudioStream *st){ return LINPHONE_VOLUME_DB_LOWEST; } -float audio_stream_get_max_volume(AudioStream *st){ +static float audio_stream_get_max_volume(AudioStream *st){ if (st && st->volsend){ float vol=0; ms_filter_call_method(st->volsend,MS_VOLUME_GET_MAX,&vol); @@ -93,11 +95,11 @@ float audio_stream_get_max_volume(AudioStream *st){ static gboolean update_audio_label(volume_ctx_t *ctx){ float volume_db=ctx->get_volume(ctx->data); gchar *result; - if (volume_db < -30) result = "No Voice"; - if (volume_db > -30 && volume_db < -15) result = "Low"; - if (volume_db > -15 && volume_db < 0) result = "Good"; - if (volume_db > 0) result = "Too loud"; - //g_message("volume_db=%f, frac=%f",volume_db,frac); + if (volume_db < -20) result = _("No voice detected"); + else if (volume_db <= -10) result = _("Too low"); + else if (volume_db < -6) result = _("Good"); + else result = _("Too loud"); + g_message("volume_max_db=%f, text=%s",volume_db,result); gtk_label_set_text(GTK_LABEL(ctx->widget),result); return TRUE; } @@ -128,26 +130,30 @@ void linphone_gtk_uninit_audio_label(GtkWidget *w){ } } -void playback_device_changed(GtkWidget *w){ +static void playback_device_changed(GtkWidget *w){ gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w)); linphone_core_set_playback_device(linphone_gtk_get_core(),sel); g_free(sel); } -void capture_device_changed(GtkWidget *capture_device){ +static void capture_device_changed(GtkWidget *capture_device){ gchar *sel; GtkWidget *mic_audiolevel; + GtkWidget *label_audiolevel; + GtkWidget *assistant=gtk_widget_get_toplevel(capture_device); AudioStream *audio_stream; mic_audiolevel = get_widget_from_assistant("mic_audiolevel"); - audio_stream = (AudioStream *) g_object_get_data(G_OBJECT(capture_device),"audio_stream"); + label_audiolevel = get_widget_from_assistant("label_audiolevel"); + audio_stream = (AudioStream *) g_object_get_data(G_OBJECT(assistant),"stream"); sel = gtk_combo_box_get_active_text(GTK_COMBO_BOX(capture_device)); linphone_core_set_capture_device(linphone_gtk_get_core(),sel); linphone_gtk_uninit_audio_meter(mic_audiolevel); + linphone_gtk_uninit_audio_label(label_audiolevel); audio_stream_stop(audio_stream); - linphone_gtk_init_audio_meter(mic_audiolevel,(get_volume_t)audio_stream_get_record_volume,audio_stream); - g_free(sel); + /*now restart the audio stream*/ + prepare(GTK_ASSISTANT(assistant)); } static void dialog_click(GtkWidget *dialog, guint response_id, GtkWidget *page){ @@ -370,7 +376,7 @@ static GtkWidget *create_end_page(){ return vbox; } -static void prepare(GtkAssistant *w, GtkWidget *p, void * data){ +static void prepare(GtkAssistant *w){ AudioStream *audio_stream = NULL; LinphoneCore *lc=linphone_gtk_get_core(); int page = gtk_assistant_get_current_page(w); @@ -380,14 +386,12 @@ static void prepare(GtkAssistant *w, GtkWidget *p, void * data){ //Speaker page if(page == 1){ MSSndCardManager *manager = ms_snd_card_manager_get(); - audio_stream = audio_stream_start_with_sndcards(&av_profile,9897,"127.0.0.1",9898,0,0,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE); - if(mic_audiolevel != NULL && audio_stream != NULL){ + audio_stream = audio_stream_start_with_sndcards(&av_profile,9898,"127.0.0.1",19898,0,0,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE); + if (mic_audiolevel != NULL && audio_stream != NULL){ g_object_set_data(G_OBJECT(audio_assistant),"stream",audio_stream); linphone_gtk_init_audio_meter(mic_audiolevel,(get_volume_t)audio_stream_get_record_volume,audio_stream); linphone_gtk_init_audio_label(label_audiolevel,(get_volume_t)audio_stream_get_max_volume,audio_stream); } - - } else if(page == 2 || page == 0){ if(mic_audiolevel != NULL && label_audiolevel != NULL){ audio_stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"stream"); diff --git a/gtk/incall_view.c b/gtk/incall_view.c index bdf54ec24..8ab6309f6 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -567,12 +567,12 @@ static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){ return TRUE; } -#define UNSIGNIFICANT_VOLUME (-26) +#define UNSIGNIFICANT_VOLUME (-23) #define SMOOTH 0.15 static gboolean update_audio_meter(volume_ctx_t *ctx){ float volume_db=ctx->get_volume(ctx->data); - float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME+3.0); + float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME-3.0); if (frac<0) frac=0; if (frac>1.0) frac=1.0; if (fraclast_value){ diff --git a/mediastreamer2 b/mediastreamer2 index aceebbf52..8663a08ed 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit aceebbf52fd94430c1aa17941f3d184be97a5b34 +Subproject commit 8663a08ed7bed3ceccaadd72e4ae3b9d5c568f31 From 9de8fe1b7659aecc3ceeb456484e7ec4c3af3ca0 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 23 Mar 2014 11:38:18 +0100 Subject: [PATCH 360/439] fix make dist --- po/POTFILES.in | 1 + 1 file changed, 1 insertion(+) diff --git a/po/POTFILES.in b/po/POTFILES.in index 988253adb..5d2aabf39 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -13,6 +13,7 @@ gtk/setupwizard.c gtk/incall_view.c gtk/loginframe.c gtk/config-fetching.c +gtk/audio_assistant.c [type: gettext/glade]gtk/main.ui [type: gettext/glade]gtk/about.ui [type: gettext/glade]gtk/contact.ui From 100e8e903e5bc930e3fffd6f071622710debe537 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 24 Mar 2014 15:11:32 +0100 Subject: [PATCH 361/439] Add audio assistant start icon --- .gitignore | 1 + configure.ac | 1 + gtk/audio_assistant.c | 8 ++++++-- gtk/linphone.h | 1 + gtk/main.c | 4 ++++ share/Makefile.am | 7 ++++--- share/audio-assistant.desktop.in | 9 +++++++++ 7 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 share/audio-assistant.desktop.in diff --git a/.gitignore b/.gitignore index 0512fc3df..2adb3b20b 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ Specfile .anjuta_sym_db.db gtk-glade/version_date.h share/linphone.desktop +share/audio-assistant.desktop Debug/ build/macos/Info-linphone.plist coreapi/help/Doxyfile diff --git a/configure.ac b/configure.ac index c38507fa4..786cb6287 100644 --- a/configure.ac +++ b/configure.ac @@ -900,6 +900,7 @@ AC_CONFIG_FILES([ share/xml/Makefile share/linphone.pc share/linphone.desktop + share/audio-assistant.desktop scripts/Makefile tools/Makefile linphone.spec diff --git a/gtk/audio_assistant.c b/gtk/audio_assistant.c index 1e5bbddeb..431fa9995 100644 --- a/gtk/audio_assistant.c +++ b/gtk/audio_assistant.c @@ -407,10 +407,14 @@ static void prepare(GtkAssistant *w){ void linphone_gtk_close_audio_assistant(GtkWidget *w){ gchar *path = g_object_get_data(G_OBJECT(audio_assistant),"path"); - g_unlink(path); + if(path != NULL){ + g_unlink(path); + } gtk_widget_destroy(w); + if(linphone_gtk_get_audio_assistant_option()){ + gtk_main_quit(); + } audio_assistant = NULL; - linphone_gtk_show_main_window(); } void linphone_gtk_audio_assistant_apply(GtkWidget *w){ diff --git a/gtk/linphone.h b/gtk/linphone.h index 910981a53..2a256cab5 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -189,6 +189,7 @@ gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_ void linphone_gtk_schedule_restart(void); void linphone_gtk_show_audio_assistant(void); +gboolean linphone_gtk_get_audio_assistant_option(void); void linphone_gtk_set_configuration_uri(void); GtkWidget * linphone_gtk_show_config_fetching(void); diff --git a/gtk/main.c b/gtk/main.c index 347abafce..2fd3fd897 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -271,6 +271,10 @@ void linphone_gtk_schedule_restart(void){ restart=TRUE; } +gboolean linphone_gtk_get_audio_assistant_option(void){ + return run_audio_assistant; +} + static void linphone_gtk_init_liblinphone(const char *config_file, const char *factory_config_file, const char *db_file) { LinphoneCoreVTable vtable={0}; diff --git a/share/Makefile.am b/share/Makefile.am index 63f15dfe4..f0df44261 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -23,7 +23,7 @@ ring_DATA=$(LINPHONE_RINGS) #to be compliant with freedesktop.org: linphone_fddir= $(datadir)/applications -linphone_fd_DATA= linphone.desktop +linphone_fd_DATA= linphone.desktop audio-assistant.desktop pkgconfigdir=$(libdir)/pkgconfig @@ -43,9 +43,10 @@ rootca.pem: cp -f $(srcdir)/archived-rootca.pem $(builddir)/rootca.pem ; \ fi -EXTRA_DIST = $(LINPHONE_SOUNDS) \ +EXTRA_DIST = $(LINPHONE_SOUNDS) \ $(LINPHONE_RINGS) \ - linphone.desktop.in \ + linphone.desktop.in \ + audio-assistant.desktop.in \ linphone.pc.in \ Makefile.inc \ archived-rootca.pem diff --git a/share/audio-assistant.desktop.in b/share/audio-assistant.desktop.in new file mode 100644 index 000000000..5e164ca2b --- /dev/null +++ b/share/audio-assistant.desktop.in @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Audio assistant +Comment=Linphone audio assistant +Comment[fr]=Assistant audio de Linphone. +Type=Application +Exec=linphone --run-audio-assistant +Icon=/usr/local/share/pixmaps/linphone/linphone.png +Terminal=false +Categories=Network;Telephony; \ No newline at end of file From a53029578d223077d2fdd70a5a83277dafc0b074 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 24 Mar 2014 15:51:02 +0100 Subject: [PATCH 362/439] Fix compilation with video disabled --- gtk/propertybox.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 494f1a5fb..86356a97b 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1280,6 +1280,7 @@ void linphone_gtk_fill_webcams(GtkWidget *pb){ } void linphone_gtk_fill_video_renderers(GtkWidget *pb){ +#ifdef VIDEO_ENABLED /* video_stream_get_default_video_renderer requires video enabled */ LinphoneCore *lc=linphone_gtk_get_core(); GtkWidget *combo=linphone_gtk_get_widget(pb,"renderers"); MSList *l=ms_filter_lookup_by_interface(MSFilterVideoDisplayInterface); @@ -1290,7 +1291,7 @@ void linphone_gtk_fill_video_renderers(GtkWidget *pb){ GtkListStore *store; GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); GtkTreeModel *model=GTK_TREE_MODEL(store=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_STRING)); - + if (current_renderer==NULL) current_renderer=video_stream_get_default_video_renderer(); gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); @@ -1308,6 +1309,7 @@ void linphone_gtk_fill_video_renderers(GtkWidget *pb){ } ms_list_free(l); if (active!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); +#endif } typedef struct { From 25e3c367483bfeeacb26fdc22d29588809be8d28 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Mon, 24 Mar 2014 16:30:01 +0100 Subject: [PATCH 363/439] Fix audio-assistant.ui gtk version --- gtk/audio_assistant.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtk/audio_assistant.ui b/gtk/audio_assistant.ui index 4fa0588c5..b8390f5d8 100644 --- a/gtk/audio_assistant.ui +++ b/gtk/audio_assistant.ui @@ -1,6 +1,6 @@ - + False From 9d31ca0e5d967b0cb1194955d9d3626312bcf150 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 24 Mar 2014 16:33:12 +0100 Subject: [PATCH 364/439] add java wrapper to LinphoneErrorInfo --- coreapi/linphonecore_jni.cc | 72 +++++++++++++++++++ java/common/org/linphone/core/ErrorInfo.java | 24 +++++++ .../org/linphone/core/LinphoneCall.java | 8 +++ .../linphone/core/LinphoneChatMessage.java | 14 ++-- .../org/linphone/core/LinphoneEvent.java | 6 ++ .../linphone/core/LinphoneProxyConfig.java | 6 ++ java/common/org/linphone/core/Reason.java | 4 ++ .../impl/org/linphone/core/ErrorInfoImpl.java | 41 +++++++++++ .../org/linphone/core/LinphoneCallImpl.java | 10 +++ .../core/LinphoneChatMessageImpl.java | 5 ++ .../org/linphone/core/LinphoneEventImpl.java | 5 ++ .../core/LinphoneProxyConfigImpl.java | 5 ++ 12 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 java/common/org/linphone/core/ErrorInfo.java create mode 100644 java/impl/org/linphone/core/ErrorInfoImpl.java diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 51346f696..b64a684f8 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1622,6 +1622,10 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getError(JNIEnv* return linphone_proxy_config_get_error((LinphoneProxyConfig *) ptr); } +extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_getErrorInfo(JNIEnv* env,jobject thiz,jlong ptr) { + return (jlong)linphone_proxy_config_get_error_info((LinphoneProxyConfig *) ptr); +} + //Auth Info extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo(JNIEnv* env @@ -2074,6 +2078,18 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getRemoteAddress( JNIEn return (jlong)linphone_call_get_remote_address((LinphoneCall*)ptr); } +extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getErrorInfo( JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jlong)linphone_call_get_error_info((LinphoneCall*)ptr); +} + +extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getReason( JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint)linphone_call_get_reason((LinphoneCall*)ptr); +} + extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getRemoteUserAgent(JNIEnv *env, jobject thiz, jlong ptr) { LinphoneCall *call = (LinphoneCall *)ptr; const char *value=linphone_call_get_remote_user_agent(call); @@ -2400,6 +2416,12 @@ extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getReason(JNIEnv* return linphone_chat_message_get_reason((LinphoneChatMessage*)ptr); } +extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getErrorInfo(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jlong)linphone_chat_message_get_error_info((LinphoneChatMessage*)ptr); +} + extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getCustomHeader(JNIEnv* env ,jobject thiz ,jlong ptr, jstring jheader_name) { @@ -3684,6 +3706,11 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getReason(JNIEnv return linphone_event_get_reason(ev); } +JNIEXPORT jlong JNICALL Java_org_linphone_core_LinphoneEventImpl_getErrorInfo(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return (jlong)linphone_event_get_error_info(ev); +} + /* * Class: org_linphone_core_LinphoneEventImpl * Method: getSubscriptionDir @@ -4616,4 +4643,49 @@ JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_isSdp200AckEn return (jboolean)linphone_core_sdp_200_ack_enabled((const LinphoneCore*)lc); } +/* Header for class org_linphone_core_ErrorInfoImpl */ +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_linphone_core_ErrorInfoImpl + * Method: getReason + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_ErrorInfoImpl_getReason(JNIEnv *env, jobject jobj, jlong ei){ + return linphone_error_info_get_reason((const LinphoneErrorInfo*)ei); +} + +/* + * Class: org_linphone_core_ErrorInfoImpl + * Method: getProtocolCode + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_ErrorInfoImpl_getProtocolCode(JNIEnv *env, jobject jobj, jlong ei){ + return linphone_error_info_get_protocol_code((const LinphoneErrorInfo*)ei); +} + +/* + * Class: org_linphone_core_ErrorInfoImpl + * Method: getPhrase + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getPhrase(JNIEnv *env, jobject jobj, jlong ei){ + const char *tmp=linphone_error_info_get_phrase((const LinphoneErrorInfo*)ei); + return tmp ? env->NewStringUTF(tmp) : NULL; +} + +/* + * Class: org_linphone_core_ErrorInfoImpl + * Method: getDetails + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getDetails(JNIEnv *env, jobject jobj, jlong ei){ + const char *tmp=linphone_error_info_get_details((const LinphoneErrorInfo*)ei); + return tmp ? env->NewStringUTF(tmp) : NULL; +} + +#ifdef __cplusplus +} +#endif diff --git a/java/common/org/linphone/core/ErrorInfo.java b/java/common/org/linphone/core/ErrorInfo.java new file mode 100644 index 000000000..348f7fd61 --- /dev/null +++ b/java/common/org/linphone/core/ErrorInfo.java @@ -0,0 +1,24 @@ +package org.linphone.core; + +public interface ErrorInfo { + /** + * Return the Reason enum corresponding to the error type. + * @return the reason. + */ + Reason getReason(); + /** + * Get the protocol code corresponding to the error (typically a SIP status code). + * @return the code. + */ + int getProtocolCode(); + /** + * Get the reason-phrase provided by the protocol (typically a SIP reason-phrase). + * @return the reason phrase. + */ + String getPhrase(); + /** + * Get details about the error, if provided by the protocol. For SIP it consists of the content of a Warning or Reason header. + * @return details about the error. + */ + String getDetails(); +} diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 62be0d638..90fe60ded 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -315,4 +315,12 @@ public interface LinphoneCall { **/ LinphoneCall getTransferTargetCall(); + Reason getReason(); + + /** + * Returns last error reported for the call. + * @return an ErrorInfo. + */ + ErrorInfo getErrorInfo(); + } diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index 7d5d8b472..356294102 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -142,8 +142,14 @@ public interface LinphoneChatMessage { */ int getStorageId(); - /** - * @return the reason if response received - */ - Reason getReason(); + /** + * @return the reason if response received + */ + Reason getReason(); + + /** + * Returns full error in case of failure when sending message. + * @return an ErrorInfo. + */ + ErrorInfo getErrorInfo(); } diff --git a/java/common/org/linphone/core/LinphoneEvent.java b/java/common/org/linphone/core/LinphoneEvent.java index cdc34d404..dcdfcfc48 100644 --- a/java/common/org/linphone/core/LinphoneEvent.java +++ b/java/common/org/linphone/core/LinphoneEvent.java @@ -58,6 +58,12 @@ public interface LinphoneEvent { */ Reason getReason(); + /** + * In case of error notified, returns the full error details. + * @return an ErrorInfo. + */ + ErrorInfo getErrorInfo(); + /** * Assign an application context to the LinphoneEvent, for later use. * @param obj diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index e613fd194..0ff1900a3 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -211,4 +211,10 @@ public interface LinphoneProxyConfig { * @return reason code. */ public Reason getError(); + + /** + * Get full error information about last error occured on the proxy config. + * @return an ErrorInfo. + */ + public ErrorInfo getErrorInfo(); } diff --git a/java/common/org/linphone/core/Reason.java b/java/common/org/linphone/core/Reason.java index d08a53e46..0d7625a36 100644 --- a/java/common/org/linphone/core/Reason.java +++ b/java/common/org/linphone/core/Reason.java @@ -84,6 +84,10 @@ public class Reason { * Server timeout */ static public Reason ServerTimeout = new Reason(19,"ServerTimeout"); + /** + * Unknown + */ + static public Reason Unknown = new Reason(20,"Unknown"); protected final int mValue; private final String mStringValue; diff --git a/java/impl/org/linphone/core/ErrorInfoImpl.java b/java/impl/org/linphone/core/ErrorInfoImpl.java new file mode 100644 index 000000000..e9b6bd5f3 --- /dev/null +++ b/java/impl/org/linphone/core/ErrorInfoImpl.java @@ -0,0 +1,41 @@ +package org.linphone.core; + +public class ErrorInfoImpl implements ErrorInfo { + private Reason mReason; + private int mCode; + private String mPhrase; + private String mDetails; + + private native int getReason(long nativePtr); + private native int getProtocolCode(long nativePtr); + private native String getPhrase(long nativePtr); + private native String getDetails(long nativePtr); + + public ErrorInfoImpl(long nativePtr){ + mReason=Reason.fromInt(getReason(nativePtr)); + mCode=getProtocolCode(nativePtr); + mPhrase=getPhrase(nativePtr); + mDetails=getDetails(nativePtr); + } + + @Override + public Reason getReason() { + return mReason; + } + + @Override + public int getProtocolCode() { + return mCode; + } + + @Override + public String getPhrase() { + return mPhrase; + } + + @Override + public String getDetails() { + return mDetails; + } + +} diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index af79eb725..66a9bf1d9 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -226,4 +226,14 @@ class LinphoneCallImpl implements LinphoneCall { public LinphoneCall getTransferTargetCall() { return (LinphoneCall)getTransferTargetCall(nativePtr); } + @Override + public Reason getReason() { + // TODO Auto-generated method stub + return null; + } + private native long getErrorInfo(long nativePtr); + @Override + public ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(nativePtr)); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 2708a82af..a891cad8b 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -100,4 +100,9 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public Reason getReason() { return Reason.fromInt(getReason(nativePtr)); } + private native long getErrorInfo(long nativePtr); + @Override + public ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(nativePtr)); + } } diff --git a/java/impl/org/linphone/core/LinphoneEventImpl.java b/java/impl/org/linphone/core/LinphoneEventImpl.java index 42d14ef20..2b4c1a71b 100644 --- a/java/impl/org/linphone/core/LinphoneEventImpl.java +++ b/java/impl/org/linphone/core/LinphoneEventImpl.java @@ -118,5 +118,10 @@ public class LinphoneEventImpl implements LinphoneEvent { else sendPublish(mNativePtr, null, null, null, null); } + private native long getErrorInfo(long nativePtr); + @Override + public ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(mNativePtr)); + } } diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 2fe08ad91..96b153733 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -207,4 +207,9 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public String getContactUriParameters() { return getContactUriParameters(nativePtr); } + private native long getErrorInfo(long nativePtr); + @Override + public ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(nativePtr)); + } } From cf25820aec64a6ecb676eae872cf106f42fb0085 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 24 Mar 2014 16:53:13 +0100 Subject: [PATCH 365/439] add new checks for ErrorInfo mechanism --- tester/eventapi_tester.c | 12 +++++++++++- tester/register_tester.c | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 49f0cdc83..5f10a5183 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -111,6 +111,8 @@ static void subscribe_test_declined(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneContent content={0}; + LinphoneEvent *lev; + const LinphoneErrorInfo *ei; MSList* lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); @@ -122,13 +124,21 @@ static void subscribe_test_declined(void) { pauline->decline_subscribe=TRUE; - linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,&content); + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,&content); + linphone_event_ref(lev); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,21000));/*yes flexisip may wait 20 secs in case of forking*/ + ei=linphone_event_get_error_info(lev); + CU_ASSERT_PTR_NOT_NULL(ei); + if (ei){ + CU_ASSERT_EQUAL(linphone_error_info_get_protocol_code(ei),603); + CU_ASSERT_PTR_NOT_NULL(linphone_error_info_get_phrase(ei)); + } CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + linphone_event_unref(lev); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } diff --git a/tester/register_tester.c b/tester/register_tester.c index 547c2cec4..28850e141 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -356,6 +356,22 @@ static void authenticated_register_with_wrong_credentials_with_params(const char /*wait for retry*/ CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&counters->number_of_auth_info_requested,4)); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,1); + + /*check the detailed error info */ + if (!user_agent || strcmp(user_agent,"tester-no-403")!=0){ + LinphoneProxyConfig *cfg=NULL; + linphone_core_get_default_proxy(mgr->lc,&cfg); + CU_ASSERT_PTR_NOT_NULL(cfg); + if (cfg){ + const LinphoneErrorInfo *ei=linphone_proxy_config_get_error_info(cfg); + const char *phrase=linphone_error_info_get_phrase(ei); + CU_ASSERT_PTR_NOT_NULL(phrase); + if (phrase) CU_ASSERT_TRUE(strcmp(phrase,"Forbidden")==0); + CU_ASSERT_EQUAL(linphone_error_info_get_protocol_code(ei),403); + CU_ASSERT_PTR_NULL(linphone_error_info_get_details(ei)); + } + + } linphone_core_manager_destroy(mgr); } static void authenticated_register_with_wrong_credentials() { From 546dcfb160e81142911837203c9c9726804287a7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 25 Mar 2014 10:58:18 +0100 Subject: [PATCH 366/439] enable real early media sending for incoming calls. --- coreapi/callbacks.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 80818be37..f7a1fa363 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -143,8 +143,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){ send_ringbacktone=TRUE; } - if (call->state==LinphoneCallIncomingEarlyMedia || - (call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){ + if ((call->state==LinphoneCallIncomingEarlyMedia || call->state==LinphoneCallOutgoingEarlyMedia) && !call->params.real_early_media){ all_muted=TRUE; } linphone_call_start_media_streams(call,all_muted,send_ringbacktone); From 51bd9c2c9c09ad409556f7d7e37602aa00c64cb3 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Tue, 25 Mar 2014 11:07:22 +0100 Subject: [PATCH 367/439] Add audio-assistant in rpm --- linphone.spec.in | 1 + 1 file changed, 1 insertion(+) diff --git a/linphone.spec.in b/linphone.spec.in index 728ad5151..eb8c65b51 100644 --- a/linphone.spec.in +++ b/linphone.spec.in @@ -85,6 +85,7 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/*.so.* %{_mandir}/* %{_datadir}/applications/%{name}.desktop +%{_datadir}/applications/audio-assistant.desktop %{_datadir}/pixmaps/linphone %{_datadir}/linphone %{_datadir}/pixmaps/linphone.png From c25273e9ca522bb096364ffddf50a68f43f70cfc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 25 Mar 2014 12:48:17 +0100 Subject: [PATCH 368/439] add C function to disable chat --- coreapi/bellesip_sal/sal_op_message.c | 21 ++++++++++++++++++--- coreapi/callbacks.c | 5 ++++- coreapi/chat.c | 25 +++++++++++++++++++++++++ coreapi/linphonecore.h | 3 +++ coreapi/private.h | 1 + include/sal/sal.h | 1 + tester/message_tester.c | 20 ++++++++++++++++++++ 7 files changed, 72 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 05f1199b8..c346347d0 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -92,6 +92,11 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve || (external_body=is_external_body(content_type)))) { SalMessage salmsg; char message_id[256]={0}; + + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=server_transaction; + belle_sip_object_ref(op->pending_server_trans); + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); @@ -120,6 +125,8 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve saliscomposing.from=from; saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); op->base.root->callbacks.is_composing_received(op,&saliscomposing); + resp = belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); belle_sip_object_unref(address); belle_sip_free(from); } else { @@ -130,14 +137,11 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve belle_sip_server_transaction_send_response(server_transaction,resp); return; } - resp = belle_sip_response_create_from_request(req,200); - belle_sip_server_transaction_send_response(server_transaction,resp); } static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; sal_process_incoming_message(op,event); - sal_op_release(op); } int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ @@ -171,6 +175,17 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co } +int sal_message_reply(SalOp *op, SalReason reason){ + if (op->pending_server_trans){ + int code=sal_reason_to_sip_code(reason); + belle_sip_response_t *resp = belle_sip_response_create_from_request( + belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_server_trans),code); + belle_sip_server_transaction_send_response(op->pending_server_trans,resp); + return 0; + }else ms_error("sal_message_reply(): no server transaction"); + return -1; +} + int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) { return sal_message_send(op,from,to,"text/plain",msg); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f7a1fa363..0daf09cd2 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -878,9 +878,12 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){ static void text_received(SalOp *op, const SalMessage *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - if (is_duplicate_msg(lc,msg->message_id)==FALSE){ + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + if (lc->chat_deny_code==LinphoneReasonNone && is_duplicate_msg(lc,msg->message_id)==FALSE){ linphone_core_message_received(lc,op,msg); } + sal_message_reply(op,lc->chat_deny_code); + if (!call) sal_op_release(op); } static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) { diff --git a/coreapi/chat.c b/coreapi/chat.c index 264d6d768..ef01b8b11 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -37,6 +37,31 @@ * @{ */ +/** + * Inconditionnaly disable incoming chat messages. + * @param lc the core + * @param deny_reason the deny reason (#LinphoneReasonNone has no effect). +**/ +void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason){ + lc->chat_deny_code=deny_reason; +} + +/** + * Enable reception of incoming chat messages. + * By default it is enabled but it can be disabled with linphone_core_disable_chat(). + * @param lc the core +**/ +void linphone_core_enable_chat(LinphoneCore *lc){ + lc->chat_deny_code=LinphoneReasonNone; +} + +/** + * Returns whether chat is enabled. +**/ +bool_t linphone_core_chat_enabled(const LinphoneCore *lc){ + return lc->chat_deny_code!=LinphoneReasonNone; +} + /** * Returns an array of chat rooms * @param lc #LinphoneCore object diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f2d4b2514..927b46a43 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1038,6 +1038,9 @@ LINPHONE_PUBLIC void linphone_core_set_chat_database_path(LinphoneCore *lc, cons LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to); LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_get_or_create_chat_room(LinphoneCore *lc, const char *to); LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr); +LINPHONE_PUBLIC void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason); +LINPHONE_PUBLIC void linphone_core_enable_chat(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_chat_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_chat_room_destroy(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message); LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming); diff --git a/coreapi/private.h b/coreapi/private.h index 18de67587..a9bd1f0bf 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -681,6 +681,7 @@ struct _LinphoneCore #endif //BUILD_UPNP belle_http_provider_t *http_provider; MSList *tones; + LinphoneReason chat_deny_code; }; diff --git a/include/sal/sal.h b/include/sal/sal.h index f508484ec..9990d099e 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -618,6 +618,7 @@ int sal_unregister(SalOp *h); /*Messaging */ 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); +int sal_message_reply(SalOp *op, SalReason reason); /*presence Subscribe/notify*/ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expires); diff --git a/tester/message_tester.c b/tester/message_tester.c index 5cf1b54a8..259727715 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -263,6 +263,25 @@ static void text_message_with_send_error(void) { linphone_core_manager_destroy(pauline); } +static void text_message_denied(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_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"); + + /*pauline doesn't want to be disturbed*/ + linphone_core_disable_chat(pauline->lc,LinphoneReasonDoNotDisturb); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,marie->lc); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static const char *info_content="blabla"; void info_message_received(LinphoneCore *lc, LinphoneCall* call, const LinphoneInfoMessage *msg){ @@ -360,6 +379,7 @@ test_t message_tests[] = { { "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 denied", text_message_denied }, { "Info message", info_message }, { "Info message with body", info_message_with_body }, { "IsComposing notification", is_composing_notification } From 2276fd70fe35e3d7132f83228b691d4fd8a92768 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 25 Mar 2014 13:11:15 +0100 Subject: [PATCH 369/439] wrap chat enablement methods to java --- coreapi/linphonecore_jni.cc | 28 +++++++ .../org/linphone/core/LinphoneCore.java | 20 +++++ .../org/linphone/core/LinphoneCoreImpl.java | 79 +++++++++++-------- 3 files changed, 95 insertions(+), 32 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index b64a684f8..fc793f2c5 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1455,6 +1455,34 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createProxyConfig(JNIEn return (jlong) proxy; } +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: disableChat + * Signature: (JI)V + */ +extern "C" JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_disableChat(JNIEnv *env, jobject jobj, jlong ptr, jint reason){ + linphone_core_disable_chat((LinphoneCore*)ptr,(LinphoneReason)reason); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: enableChat + * Signature: (J)V + */ +extern "C" JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableChat(JNIEnv *env, jobject jobj, jlong ptr){ + linphone_core_enable_chat((LinphoneCore*)ptr); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: chatEnabled + * Signature: (J)Z + */ +extern "C" JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_chatEnabled(JNIEnv *env, jobject jobj, jlong ptr){ + return (jboolean) linphone_core_chat_enabled((LinphoneCore*)ptr); +} + + //ProxyConfig extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) { diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 5a211736c..72164a3fe 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1564,5 +1564,25 @@ public interface LinphoneCore { */ public boolean isSdp200AckEnabled(); + /** + * Inconditionnaly disable incoming chat messages. + * @param lc the core + * @param deny_reason the deny reason (using ReasonNone has no effect). + **/ + public void disableChat(Reason denycode); + + /** + * Enable reception of incoming chat messages. + * By default it is enabled but it can be disabled with linphone_core_disable_chat(). + * @param lc the core + **/ + public void enableChat(); + + + /** + * Returns whether chat is enabled. + * @return true if chat is enabled, false otherwise. + **/ + public boolean chatEnabled(); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 5eeb0ac37..16ca38e36 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -966,79 +966,79 @@ class LinphoneCoreImpl implements LinphoneCore { } private native boolean upnpAvailable(long ptr); - public boolean upnpAvailable() { + public synchronized boolean upnpAvailable() { return upnpAvailable(nativePtr); } private native int getUpnpState(long ptr); - public UpnpState getUpnpState() { + public synchronized UpnpState getUpnpState() { return UpnpState.fromInt(getUpnpState(nativePtr)); } private native String getUpnpExternalIpaddress(long ptr); - public String getUpnpExternalIpaddress() { + public synchronized String getUpnpExternalIpaddress() { return getUpnpExternalIpaddress(nativePtr); } private native int startConferenceRecording(long nativePtr, String path); @Override - public void startConferenceRecording(String path) { + public synchronized void startConferenceRecording(String path) { startConferenceRecording(nativePtr,path); } private native int stopConferenceRecording(long nativePtr); @Override - public void stopConferenceRecording() { + public synchronized void stopConferenceRecording() { stopConferenceRecording(nativePtr); } @Override - public PayloadType findPayloadType(String mime) { + public synchronized 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) { + public synchronized void setSipDscp(int dscp) { setSipDscp(nativePtr,dscp); } private native int getSipDscp(long nativePtr); @Override - public int getSipDscp() { + public synchronized int getSipDscp() { return getSipDscp(nativePtr); } private native void setAudioDscp(long nativePtr, int dscp); @Override - public void setAudioDscp(int dscp) { + public synchronized void setAudioDscp(int dscp) { setAudioDscp(nativePtr, dscp); } private native int getAudioDscp(long nativePtr); @Override - public int getAudioDscp() { + public synchronized int getAudioDscp() { return getAudioDscp(nativePtr); } private native void setVideoDscp(long nativePtr, int dscp); @Override - public void setVideoDscp(int dscp) { + public synchronized void setVideoDscp(int dscp) { setVideoDscp(nativePtr,dscp); } private native int getVideoDscp(long nativePtr); @Override - public int getVideoDscp() { + public synchronized int getVideoDscp() { return getVideoDscp(nativePtr); } private native long createInfoMessage(long nativeptr); @Override - public LinphoneInfoMessage createInfoMessage() { + public synchronized LinphoneInfoMessage createInfoMessage() { return new LinphoneInfoMessageImpl(createInfoMessage(nativePtr)); } private native Object subscribe(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, byte data [], String encoding); @Override - public LinphoneEvent subscribe(LinphoneAddress resource, String eventname, + public synchronized LinphoneEvent subscribe(LinphoneAddress resource, String eventname, int expires, LinphoneContent content) { return (LinphoneEvent)subscribe(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getData() : null, @@ -1046,7 +1046,7 @@ class LinphoneCoreImpl implements LinphoneCore { } private native Object publish(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, byte data [], String encoding); @Override - public LinphoneEvent publish(LinphoneAddress resource, String eventname, + public synchronized LinphoneEvent publish(LinphoneAddress resource, String eventname, int expires, LinphoneContent content) { return (LinphoneEvent)publish(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getData() : null, @@ -1055,18 +1055,18 @@ class LinphoneCoreImpl implements LinphoneCore { private native Object createSubscribe(long core, long addr, String event, int expires); @Override - public LinphoneEvent createSubscribe(LinphoneAddress resource, + public synchronized LinphoneEvent createSubscribe(LinphoneAddress resource, String event, int expires) { return (LinphoneEvent)createSubscribe(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, event, expires); } private native Object createPublish(long core, long addr, String event, int expires); @Override - public LinphoneEvent createPublish(LinphoneAddress resource, + public synchronized LinphoneEvent createPublish(LinphoneAddress resource, String event, int expires) { return (LinphoneEvent)createPublish(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, event, expires); } - public void setChatDatabasePath(String path) { + public synchronized void setChatDatabasePath(String path) { setChatDatabasePath(nativePtr, path); } @@ -1082,7 +1082,7 @@ class LinphoneCoreImpl implements LinphoneCore { return proxies; } - public LinphoneAuthInfo[] getAuthInfosList() { + public synchronized LinphoneAuthInfo[] getAuthInfosList() { long[] typesPtr = getAuthInfosList(nativePtr); if (typesPtr == null) return null; @@ -1095,7 +1095,7 @@ class LinphoneCoreImpl implements LinphoneCore { return authInfos; } - public LinphoneAuthInfo findAuthInfo(String username, String realm, String domain) { + public synchronized LinphoneAuthInfo findAuthInfo(String username, String realm, String domain) { long ptr = findAuthInfos(nativePtr, username, realm, domain); if (ptr == 0) return null; @@ -1104,7 +1104,7 @@ class LinphoneCoreImpl implements LinphoneCore { } private native LinphoneCall startReferedCall(long corePtr, long callptr, long paramsPtr); @Override - public LinphoneCall startReferedCall(LinphoneCall call, + public synchronized LinphoneCall startReferedCall(LinphoneCall call, LinphoneCallParams params) { long ptrParams =((LinphoneCallParamsImpl)params).nativePtr; return startReferedCall(nativePtr, getCallPtr(call), ptrParams); @@ -1112,58 +1112,73 @@ class LinphoneCoreImpl implements LinphoneCore { private native String[] listSupportedVideoResolutions(long ptr); @Override - public String[] getSupportedVideoSizes() { + public synchronized String[] getSupportedVideoSizes() { return listSupportedVideoResolutions(nativePtr); } @Override - public int migrateToMultiTransport() { + public synchronized int migrateToMultiTransport() { return migrateToMultiTransport(nativePtr); } private native boolean acceptEarlyMedia(long lc, long call); @Override - public boolean acceptEarlyMedia(LinphoneCall call) { + public synchronized boolean acceptEarlyMedia(LinphoneCall call) { return acceptEarlyMedia(nativePtr, getCallPtr(call)); } private native boolean acceptEarlyMediaWithParams(long lc, long call, long params); @Override - public boolean acceptEarlyMediaWithParams(LinphoneCall call, + public synchronized boolean acceptEarlyMediaWithParams(LinphoneCall call, LinphoneCallParams params) { long ptrParams = params != null ? ((LinphoneCallParamsImpl) params).nativePtr : 0; return acceptEarlyMediaWithParams(nativePtr, getCallPtr(call), ptrParams); } @Override - public LinphoneProxyConfig createProxyConfig() { + public synchronized LinphoneProxyConfig createProxyConfig() { return new LinphoneProxyConfigImpl(createProxyConfig(nativePtr)); } @Override - public void setCallErrorTone(Reason reason, String path) { + public synchronized void setCallErrorTone(Reason reason, String path) { setCallErrorTone(nativePtr, reason.mValue, path); } private native void setMtu(long nativePtr, int mtu); @Override - public void setMtu(int mtu) { + public synchronized void setMtu(int mtu) { setMtu(nativePtr,mtu); } private native int getMtu(long nativePtr); @Override - public int getMtu() { + public synchronized int getMtu() { return getMtu(nativePtr); } @Override - public void enableSdp200Ack(boolean enable) { + public synchronized void enableSdp200Ack(boolean enable) { enableSdp200Ack(nativePtr,enable); } @Override - public boolean isSdp200AckEnabled() { + public synchronized boolean isSdp200AckEnabled() { return isSdp200AckEnabled(nativePtr); } private native void setTone(long nativePtr, int id, String wavfile); @Override - public void setTone(ToneID id, String wavfile) { + public synchronized void setTone(ToneID id, String wavfile) { setTone(nativePtr, id.mValue, wavfile); } + private native void disableChat(long ptr, int denycode); + @Override + public synchronized void disableChat(Reason denycode) { + disableChat(nativePtr,denycode.mValue); + } + private native void enableChat(long ptr); + @Override + public synchronized void enableChat() { + enableChat(nativePtr); + } + private native boolean chatEnabled(long ptr); + @Override + public synchronized boolean chatEnabled() { + return chatEnabled(nativePtr); + } } From 21319737c9ab566f03f2c20f1bc3d9a0a41bd93b Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 25 Mar 2014 17:51:52 +0100 Subject: [PATCH 370/439] MS2:downgrade speex resampler quality to min in case of arm with no neon --- .cproject | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.cproject b/.cproject index 45790510b..07ef2412f 100644 --- a/.cproject +++ b/.cproject @@ -22,7 +22,7 @@ - + diff --git a/mediastreamer2 b/mediastreamer2 index 8663a08ed..771991709 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8663a08ed7bed3ceccaadd72e4ae3b9d5c568f31 +Subproject commit 77199170953e84b4301ad42eeebde9cd7f338b12 From 838a3c3ed4590cd1e3b5056d3f35f0d9e330e06a Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 25 Mar 2014 18:11:04 +0100 Subject: [PATCH 371/439] MS2:fix for android build in msresampler --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 771991709..6530cce9c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 77199170953e84b4301ad42eeebde9cd7f338b12 +Subproject commit 6530cce9c2062bdbbfdd0e01feac32243c3310f2 From 250495034edf5837cb0a652fd6dfd1232f060918 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 25 Mar 2014 22:47:35 +0100 Subject: [PATCH 372/439] rely on belle-sip ability to choose SIP transport random port using bind(). --- coreapi/bellesip_sal/sal_impl.c | 16 ++++++++++---- coreapi/linphonecore.c | 37 +++++++++++---------------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index be3c9ba17..ff6c0c17a 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -537,10 +537,18 @@ int sal_transport_available(Sal *sal, SalTransport t){ int sal_add_listen_port(Sal *ctx, SalAddress* addr){ int result; - belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack - ,sal_address_get_domain(addr) - ,sal_address_get_port(addr) - ,sal_transport_to_string(sal_address_get_transport(addr))); + belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack, + sal_address_get_domain(addr), + sal_address_get_port(addr), + sal_transport_to_string(sal_address_get_transport(addr))); + if (sal_address_get_port(addr)==-1 && lp==NULL){ + int random_port=(0xDFFF&random())+1024; + ms_warning("This version of belle-sip doesn't support random port, choosing one here."); + lp = belle_sip_stack_create_listening_point(ctx->stack, + sal_address_get_domain(addr), + random_port, + sal_transport_to_string(sal_address_get_transport(addr))); + } if (lp) { belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive); result = belle_sip_provider_add_listening_point(ctx->prov,lp); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9cd36d0fd..b5cda087b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1918,25 +1918,23 @@ static int apply_transports(LinphoneCore *lc){ anyaddr="0.0.0.0"; sal_unlisten_ports(sal); - if (tr->udp_port>0){ + if (tr->udp_port!=0){ if (sal_listen_port (sal,anyaddr,tr->udp_port,SalTransportUDP,FALSE)!=0){ transport_error(lc,"udp",tr->udp_port); return -1; } } - if (tr->tcp_port>0){ + if (tr->tcp_port!=0){ if (sal_listen_port (sal,anyaddr,tr->tcp_port,SalTransportTCP,FALSE)!=0){ transport_error(lc,"tcp",tr->tcp_port); } } - if (tr->tls_port>0){ + if (tr->tls_port!=0){ if (sal_listen_port (sal,anyaddr,tr->tls_port,SalTransportTLS,TRUE)!=0){ transport_error(lc,"tls",tr->tls_port); } } - apply_user_agent(lc); - return 0; } @@ -1957,31 +1955,20 @@ bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTra **/ 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 (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) { /*legacy random mode*/ if (tr.udp_port>0){ - tr.udp_port=random_port; - tr.tls_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ - }else if (tr.tcp_port>0){ - tr.tcp_port=random_port; - tr.tls_port=tr.udp_port=0; /*make sure only one transport is active at a time*/ - }else if (tr.tls_port>0){ - tr.tls_port=random_port; - tr.udp_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ - } else { - tr.udp_port=random_port; + tr.udp_port=LC_SIP_TRANSPORT_RANDOM; + } + if (tr.tcp_port>0){ + tr.tcp_port=LC_SIP_TRANSPORT_RANDOM; + } + if (tr.tls_port>0){ + tr.tls_port=LC_SIP_TRANSPORT_RANDOM; + }else { + tr.udp_port=LC_SIP_TRANSPORT_RANDOM; } - } - 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){ From 266207c5f09467696f4da70828e392190731155d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 26 Mar 2014 11:30:07 +0100 Subject: [PATCH 373/439] change behavior of linphone_core_get_sip_transports() if random port selection was specified. Only linphone_core_get_sip_transports_used() will return the real port if random port selection was specified. --- coreapi/bellesip_sal/sal_impl.c | 14 +++++++++++++- coreapi/linphonecore.c | 26 +++++++++++++++++++------- coreapi/linphonecore.h | 2 ++ include/sal/sal.h | 1 + 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index ff6c0c17a..04a3e093d 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -569,22 +569,34 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i sal_address_destroy(sal_addr); return result; } + static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) { belle_sip_provider_remove_listening_point(prov,lp); } + +int sal_get_listening_port(Sal *ctx, SalTransport tr){ + const char *tpn=sal_transport_to_string(tr); + belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov, tpn); + if (lp){ + return belle_sip_listening_point_get_port(lp); + } + return 0; +} + int sal_unlisten_ports(Sal *ctx){ const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov); belle_sip_list_t * tmp_list = belle_sip_list_copy(lps); belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov); belle_sip_list_free(tmp_list); - ms_message("sal_unlisten_ports done"); return 0; } + ortp_socket_t sal_get_socket(Sal *ctx){ ms_warning("sal_get_socket is deprecated"); return -1; } + void sal_set_user_agent(Sal *ctx, const char *user_agent){ belle_sip_header_user_agent_set_products(ctx->user_agent,NULL); belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b5cda087b..69680e9d2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1521,7 +1521,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(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); @@ -1833,8 +1833,9 @@ void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833) **/ int linphone_core_get_sip_port(LinphoneCore *lc) { - LCSipTransports *tr=&lc->sip_conf.transports; - return tr->udp_port>0 ? tr->udp_port : (tr->tcp_port > 0 ? tr->tcp_port : tr->tls_port); + LCSipTransports tr; + linphone_core_get_sip_transports_used(lc,&tr); + return tr.udp_port>0 ? tr.udp_port : (tr.tcp_port > 0 ? tr.tcp_port : tr.tls_port); } #if !USE_BELLE_SIP @@ -1949,7 +1950,7 @@ bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTra * Sets the ports to be used for each of transport (UDP or TCP) * * A zero value port for a given transport means the transport - * is not used. + * is not used. A value of LC_SIP_TRANSPORT_RANDOM (-1) means the port is to be choosen randomly by the system. * * @ingroup network_parameters **/ @@ -1990,9 +1991,9 @@ int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * t } /** - * Retrieves the ports used for each transport (udp, tcp). + * Retrieves the port configuration used for each transport (udp, tcp, tls). * A zero value port for a given transport means the transport - * is not used. + * is not used. A value of LC_SIP_TRANSPORT_RANDOM (-1) means the port is to be choosen randomly by the system. * @ingroup network_parameters **/ int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *tr){ @@ -2000,6 +2001,18 @@ int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *tr){ return 0; } +/** + * Retrieves the real port number assigned for each sip transport (udp, tcp, tls). + * A zero value means that the transport is not activated. + * If LC_SIP_TRANSPORT_RANDOM was passed to linphone_core_set_sip_transports(), the random port choosed by the system is returned. + * @ingroup network_parameters + * @param tr a LCSipTransports structure. +**/ +void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr){ + tr->udp_port=sal_get_listening_port(lc->sal,SalTransportUDP); + tr->tcp_port=sal_get_listening_port(lc->sal,SalTransportTCP); + tr->tls_port=sal_get_listening_port(lc->sal,SalTransportTLS); +} /** * Sets the UDP port to be used by SIP. * @@ -2770,7 +2783,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const lc->vtable.display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); return NULL; } - linphone_core_get_default_proxy(lc,&proxy); real_url=linphone_address_as_string(addr); proxy=linphone_core_lookup_known_proxy(lc,addr); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 927b46a43..12b550a6f 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1722,6 +1722,8 @@ LINPHONE_PUBLIC int linphone_core_set_sip_transports(LinphoneCore *lc, const LCS LINPHONE_PUBLIC int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transports); +LINPHONE_PUBLIC void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr); + LINPHONE_PUBLIC bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp); /** * diff --git a/include/sal/sal.h b/include/sal/sal.h index 9990d099e..5bc5264a2 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -501,6 +501,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_get_listening_port(Sal *ctx, SalTransport tr); int sal_unlisten_ports(Sal *ctx); int sal_transport_available(Sal *ctx, SalTransport t); void sal_set_dscp(Sal *ctx, int dscp); From 15e98c24e842a2c0862bcc54711213a4149a8e38 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Wed, 26 Mar 2014 15:09:17 +0100 Subject: [PATCH 374/439] branch to oRTP with zrtp --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index b2e5f313e..d3a18ddcf 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b2e5f313e6f245588751835ccd01bcd5dc2e8b1e +Subproject commit d3a18ddcf22f20480c7a1d9e38819e375d3c4d05 From 1c3714327f4cd9fe75229179ae8344d76804a2da Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 26 Mar 2014 16:58:13 +0100 Subject: [PATCH 375/439] Do not use raw attributes to get values. --- coreapi/bellesip_sal/sal_sdp.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 3faa7a063..b2f106cef 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -321,8 +321,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { belle_sip_list_t *attribute_it; - const belle_sdp_attribute_t *attribute; - const belle_sdp_raw_attribute_t *raw_attribute; + belle_sdp_attribute_t *attribute; char tmp[256], tmp2[256]; int valid_count = 0; int nb; @@ -332,10 +331,9 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med ; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; attribute_it=attribute_it->next ) { attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data ); - raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute); - if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_raw_attribute_get_value ( raw_attribute ) !=NULL ) { - nb = sscanf ( belle_sdp_raw_attribute_get_value ( raw_attribute ), "%d %256s inline:%256s", + 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 ); @@ -362,7 +360,7 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med valid_count++; } } else { - ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_raw_attribute_get_value ( raw_attribute ),nb ); + ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb ); } } } @@ -371,17 +369,15 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { belle_sip_list_t *attribute_it; - const belle_sdp_attribute_t *attribute; - const belle_sdp_raw_attribute_t *raw_attribute; + belle_sdp_attribute_t *attribute; const char *att_name; const char *value; int nb_ice_candidates = 0; for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { attribute=BELLE_SDP_ATTRIBUTE(attribute_it->data); - raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute); att_name = belle_sdp_attribute_get_name(attribute); - value = belle_sdp_raw_attribute_get_value(raw_attribute); + value = belle_sdp_attribute_get_value(attribute); if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; @@ -473,8 +469,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, SalStreamDescription *stream; belle_sdp_connection_t* cnx; belle_sdp_media_t* media; - const belle_sdp_attribute_t* attribute; - const belle_sdp_raw_attribute_t* raw_attribute; + belle_sdp_attribute_t* attribute; const char* value; const char *mtype,*proto; @@ -536,8 +531,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, 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"); - raw_attribute=BELLE_SDP_RAW_ATTRIBUTE(attribute); - if (attribute && (value=belle_sdp_raw_attribute_get_value(raw_attribute))!=NULL){ + 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) { From 8a292b30ccd1236b472f0665187a92156c951ec5 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 26 Mar 2014 17:09:02 +0100 Subject: [PATCH 376/439] fix generic publishes not properly terminated. --- coreapi/event.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/coreapi/event.c b/coreapi/event.c index e4d66db3e..731412153 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -107,6 +107,9 @@ void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState s if (lc->vtable.publish_state_changed){ lc->vtable.publish_state_changed(lev->lc,lev,state); } + if (state==LinphonePublishCleared){ + linphone_event_unref(lev); + } } } @@ -291,7 +294,8 @@ void linphone_event_terminate(LinphoneEvent *lev){ if (lev->publish_state!=LinphonePublishNone){ if (lev->publish_state==LinphonePublishOk){ sal_publish(lev->op,NULL,NULL,NULL,0,NULL); - } + }else sal_op_stop_refreshing(lev->op); + linphone_event_set_publish_state(lev,LinphonePublishCleared); return; } From 3013fd8ae240ffafc4ec25e7d375bc4ea9d8b737 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 26 Mar 2014 17:51:47 +0100 Subject: [PATCH 377/439] allow configuration of root_ca before provisioning, so that it can be used for https fetching --- coreapi/bellesip_sal/sal_impl.c | 2 +- coreapi/linphonecore.c | 27 ++++++++++++++++++++++++--- coreapi/lpconfig.c | 3 ++- coreapi/private.h | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 04a3e093d..c0340e56a 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -552,7 +552,7 @@ 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); + if (sal_address_get_transport(addr)==SalTransportTLS) set_tls_properties(ctx); } else { return -1; } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 69680e9d2..e5eaea9ca 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -615,11 +615,13 @@ static void sound_config_read(LinphoneCore *lc) static void certificates_config_read(LinphoneCore *lc) { + const char *rootca; #ifdef __linux - sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs")); + rootca=lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs"); #else - sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE)); + rootca=lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE); #endif + linphone_core_set_root_ca(lc,rootca); linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); } @@ -1369,6 +1371,8 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab lc->network_last_status = FALSE; lc->http_provider = belle_sip_stack_create_http_provider(sal_get_belle_sip_stack(lc->sal), "0.0.0.0"); + lc->http_verify_policy = belle_tls_verify_policy_new(); + belle_http_provider_set_tls_verify_policy(lc->http_provider,lc->http_verify_policy); certificates_config_read(lc); @@ -4347,6 +4351,10 @@ const char *linphone_core_get_ring(const LinphoneCore *lc){ **/ void linphone_core_set_root_ca(LinphoneCore *lc,const char *path){ sal_set_root_ca(lc->sal, path); + if (lc->http_verify_policy){ + belle_tls_verify_policy_set_root_ca(lc->http_verify_policy,path); + } + lp_config_set_string(lc->config,"sip","root_ca",path); } /** @@ -4357,7 +4365,7 @@ void linphone_core_set_root_ca(LinphoneCore *lc,const char *path){ * @ingroup initializing **/ const char *linphone_core_get_root_ca(LinphoneCore *lc){ - return sal_get_root_ca(lc->sal); + return lp_config_get_string(lc->config,"sip","root_ca",NULL); } /** @@ -4367,6 +4375,10 @@ const char *linphone_core_get_root_ca(LinphoneCore *lc){ **/ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ sal_verify_server_certificates(lc->sal,yesno); + if (lc->http_verify_policy){ + belle_tls_verify_policy_set_exceptions(lc->http_verify_policy, yesno ? 0 : BELLE_TLS_VERIFY_ANY_REASON); + } + lp_config_set_int(lc->config,"sip","verify_server_certs",yesno); } /** @@ -4375,6 +4387,10 @@ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ **/ void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){ sal_verify_server_cn(lc->sal,yesno); + if (lc->http_verify_policy){ + belle_tls_verify_policy_set_exceptions(lc->http_verify_policy, yesno ? 0 : BELLE_TLS_VERIFY_CN_MISMATCH); + } + lp_config_set_int(lc->config,"sip","verify_server_cn",yesno); } static void notify_end_of_ring(void *ud, MSFilter *f, unsigned int event, void *arg){ @@ -5613,6 +5629,11 @@ void net_config_uninit(LinphoneCore *lc) if (lc->http_provider) { belle_sip_object_unref(lc->http_provider); + lc->http_provider=NULL; + } + if (lc->http_verify_policy){ + belle_sip_object_unref(lc->http_verify_policy); + lc->http_verify_policy=NULL; } if (config->stun_server!=NULL){ ms_free(config->stun_server); diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index feaff8cd1..8df196df2 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -324,8 +324,9 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename){ } void lp_item_set_value(LpItem *item, const char *value){ - ortp_free(item->value); + char *prev_value=item->value; item->value=ortp_strdup(value); + ortp_free(prev_value); } diff --git a/coreapi/private.h b/coreapi/private.h index a9bd1f0bf..6f421e95e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -680,6 +680,7 @@ struct _LinphoneCore UpnpContext *upnp; #endif //BUILD_UPNP belle_http_provider_t *http_provider; + belle_tls_verify_policy_t *http_verify_policy; MSList *tones; LinphoneReason chat_deny_code; }; From fe3a59ed6924c3ddde17053a25e86b2eb161782e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 27 Mar 2014 10:32:57 +0100 Subject: [PATCH 378/439] destroy http provider before sal is destroyed, otherwise the belle_sip_stack is already destroyed when destroying the provider. --- coreapi/linphonecore.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e5eaea9ca..52ef011c0 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5627,14 +5627,6 @@ void net_config_uninit(LinphoneCore *lc) { net_config_t *config=&lc->net_conf; - if (lc->http_provider) { - belle_sip_object_unref(lc->http_provider); - lc->http_provider=NULL; - } - if (lc->http_verify_policy){ - belle_sip_object_unref(lc->http_verify_policy); - lc->http_verify_policy=NULL; - } if (config->stun_server!=NULL){ ms_free(config->stun_server); } @@ -5709,6 +5701,14 @@ void sip_config_uninit(LinphoneCore *lc) sal_reset_transports(lc->sal); sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/ + if (lc->http_provider) { + belle_sip_object_unref(lc->http_provider); + lc->http_provider=NULL; + } + if (lc->http_verify_policy){ + belle_sip_object_unref(lc->http_verify_policy); + lc->http_verify_policy=NULL; + } sal_iterate(lc->sal); /*make sure event are purged*/ sal_uninit(lc->sal); lc->sal=NULL; From 4341b43ff0fcacd4a98be5dfc2846f2dca3a81f1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 27 Mar 2014 11:29:23 +0100 Subject: [PATCH 379/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6530cce9c..17471b986 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6530cce9c2062bdbbfdd0e01feac32243c3310f2 +Subproject commit 17471b98625bc6096427351ba78f290740d15265 From a191c392244a8e49046419c799e150f06cd331ff Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 27 Mar 2014 17:19:01 +0100 Subject: [PATCH 380/439] fix bug around legacy sip_random_port property --- coreapi/linphonecore.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 52ef011c0..fa94234a1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1971,8 +1971,6 @@ int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * t } if (tr.tls_port>0){ tr.tls_port=LC_SIP_TRANSPORT_RANDOM; - }else { - tr.udp_port=LC_SIP_TRANSPORT_RANDOM; } } From 1a05114e49a01a9c9317967ce66c67c5c7d59aaf Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 28 Mar 2014 14:25:32 +0100 Subject: [PATCH 381/439] Use #define instead of enum. --- coreapi/linphonecall.c | 8 ++++---- coreapi/linphonecore.h | 15 +++------------ 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4ff3537fb..2d200c8cf 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2706,7 +2706,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; - call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LinphoneCallStatsReceivedRTCPUpdate; + call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; 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]); @@ -2716,7 +2716,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; - call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LinphoneCallStatsSentRTCPUpdate; + call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; 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]); @@ -2751,7 +2751,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; - call->stats[LINPHONE_CALL_STATS_AUDIO].updated = LinphoneCallStatsReceivedRTCPUpdate; + call->stats[LINPHONE_CALL_STATS_AUDIO].updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; 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]); @@ -2761,7 +2761,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; - call->stats[LINPHONE_CALL_STATS_AUDIO].updated = LinphoneCallStatsSentRTCPUpdate; + call->stats[LINPHONE_CALL_STATS_AUDIO].updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; 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]); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 12b550a6f..f4f34b8c6 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -577,19 +577,10 @@ enum _LinphoneUpnpState{ **/ typedef enum _LinphoneUpnpState LinphoneUpnpState; -/** - * Enum describing what has been updated in a LinphoneCallStats object. -**/ -enum _LinphoneCallStatsRTCPUpdate { - LinphoneCallStatsReceivedRTCPUpdate, /**< received_rtcp field of LinphoneCallStats object has been updated */ - LinphoneCallStatsSentRTCPUpdate /**< sent_rtcp field of LinphoneCallStats object has been updated */ -}; -/** - * Enum describing what has been updated in a LinphoneCallStats object. -**/ +#define LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE (1 << 0) /**< received_rtcp field of LinphoneCallStats object has been updated */ +#define LINPHONE_CALL_STATS_SENT_RTCP_UPDATE (1 << 1) /**< sent_rtcp field of LinphoneCallStats object has been updated */ -typedef enum _LinphoneCallStatsRTCPUpdate LinphoneCallStatsRTCPUpdate; /** * The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams. @@ -621,7 +612,7 @@ struct _LinphoneCallStats { float upload_bandwidth; /** Date: Fri, 28 Mar 2014 17:12:49 +0100 Subject: [PATCH 382/439] fix bad enum cast and invalid enum translation --- coreapi/callbacks.c | 2 +- coreapi/misc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 0daf09cd2..cb88095c7 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -882,7 +882,7 @@ static void text_received(SalOp *op, const SalMessage *msg){ if (lc->chat_deny_code==LinphoneReasonNone && is_duplicate_msg(lc,msg->message_id)==FALSE){ linphone_core_message_received(lc,op,msg); } - sal_message_reply(op,lc->chat_deny_code); + sal_message_reply(op,linphone_reason_to_sal(lc->chat_deny_code)); if (!call) sal_op_release(op); } diff --git a/coreapi/misc.c b/coreapi/misc.c index 53a4811a9..4c9834053 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1100,9 +1100,9 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ SalReason linphone_reason_to_sal(LinphoneReason reason){ switch(reason){ case LinphoneReasonNone: - return SalReasonUnknown; + return SalReasonNone; case LinphoneReasonNoResponse: - return SalReasonUnknown; + return SalReasonRequestTimeout; case LinphoneReasonForbidden: return SalReasonForbidden; case LinphoneReasonDeclined: From e42a8d15c07222544ac1078eb4ac15a8da31a2a0 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 31 Mar 2014 12:02:19 +0200 Subject: [PATCH 383/439] Update Makefile and oRTP to switch to bzrtp --- build/android/Android.mk | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index 47098be79..f009cf295 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -201,7 +201,7 @@ LOCAL_CFLAGS += $(LIBLINPHONE_EXTENDED_CFLAGS) ifeq ($(BUILD_GPLV3_ZRTP),1) LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone - LOCAL_SHARED_LIBRARIES += libzrtpcpp + LOCAL_SHARED_LIBRARIES += libbzrtp endif ifeq ($(BUILD_SRTP),1) diff --git a/oRTP b/oRTP index b2e5f313e..d3a18ddcf 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b2e5f313e6f245588751835ccd01bcd5dc2e8b1e +Subproject commit d3a18ddcf22f20480c7a1d9e38819e375d3c4d05 From 6d7b96c4fc4c073db957eb11e94fc9a078369f99 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 31 Mar 2014 12:17:13 +0200 Subject: [PATCH 384/439] update oRTP module to get correct android makefile --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index d3a18ddcf..04f2c4bff 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit d3a18ddcf22f20480c7a1d9e38819e375d3c4d05 +Subproject commit 04f2c4bff871c108fd645f6f16a3164f9fa42769 From 9ff080e19cdf70c6a065cb10dbdd837663c767e3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 1 Apr 2014 14:01:28 +0200 Subject: [PATCH 385/439] Update oRTP and ms2 submodules for RTCP XR. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 17471b986..9753c73f3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 17471b98625bc6096427351ba78f290740d15265 +Subproject commit 9753c73f37f302ef3c813c7d973da03a7c31b5bb diff --git a/oRTP b/oRTP index c0418933b..cbfd8bd5c 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit c0418933b7ce4765993b7304809e43df6ed392dd +Subproject commit cbfd8bd5c475259ddf828417e520fb7c58dcb854 From 97ef67377cfb3ee4efade953b9bc3b3023c402ac Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 1 Apr 2014 22:43:23 +0200 Subject: [PATCH 386/439] update ms2 and oRTP, add documentation for zrtp related functions. Fix bug about sesion name not taken into SDP answers. --- coreapi/linphonecall.c | 15 +++++++++++++++ coreapi/offeranswer.c | 2 ++ mediastreamer2 | 2 +- oRTP | 2 +- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2d200c8cf..e4cac3a33 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -82,6 +82,14 @@ const char* linphone_call_get_authentication_token(LinphoneCall *call){ return call->auth_token; } +/** + * Returns whether ZRTP authentication token is verified. + * If not, it must be verified by users as described in ZRTP procedure. + * Once done, the application must inform of the results with linphone_call_set_authentication_token_verified(). + * @param call the LinphoneCall + * @return TRUE if authentication token is verifed, false otherwise. + * @ingroup call_control +**/ bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){ return call->auth_token_verified; } @@ -172,6 +180,13 @@ static void linphone_call_audiostream_auth_token_ready(void *data, const char* a ms_message("Authentication token is %s (%s)", auth_token, verified?"verified":"unverified"); } +/** + * Set the result of ZRTP short code verification by user. + * If remote party also does the same, it will update the ZRTP cache so that user's verification will not be required for the two users. + * @param call the LinphoneCall + * @param verified whether the ZRTP SAS is verified. + * @ingroup call_control +**/ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified){ if (call->audiostream==NULL){ ms_error("linphone_call_set_authentication_token_verified(): No audio stream"); diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index b9f8d4c82..caece9835 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -388,6 +388,8 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities strcpy(result->ice_ufrag, local_capabilities->ice_ufrag); result->ice_lite = local_capabilities->ice_lite; result->ice_completed = local_capabilities->ice_completed; + + strcpy(result->name,local_capabilities->name); // Handle session RTCP XR attribute memset(&result->rtcp_xr, 0, sizeof(result->rtcp_xr)); diff --git a/mediastreamer2 b/mediastreamer2 index fa2231095..c3593dcba 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit fa22310955303f6a2185fec8c5610aa6f24b46fb +Subproject commit c3593dcba131ae28837f10d9f01c0500f1ebffe9 diff --git a/oRTP b/oRTP index dc4197cfc..5008a70e0 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit dc4197cfceb4074018a0b7ad22a3c24fa454c129 +Subproject commit 5008a70e077b3706de4a48374f162f93071b4d08 From d26a93eaacc545792fd6a1683bddc5a33293c80c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 2 Apr 2014 11:57:26 +0200 Subject: [PATCH 387/439] Fix crash on Android --- coreapi/linphonecore_jni.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index fc793f2c5..f5cc41bb9 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -805,8 +805,8 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setChatDatabasePath(JNIE } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv* env, jobject thiz, jlong lc, jstring jdisplayname, jstring jusername) { - const char* displayname = env->GetStringUTFChars(jdisplayname, NULL); - const char* username = env->GetStringUTFChars(jusername, NULL); + const char* displayname = jdisplayname ? env->GetStringUTFChars(jdisplayname, NULL) : NULL; + const char* username = jusername ? env->GetStringUTFChars(jusername, NULL) : NULL; LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc); if (parsed != NULL) { @@ -816,8 +816,8 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv linphone_core_set_primary_contact((LinphoneCore*)lc, contact); } - env->ReleaseStringUTFChars(jdisplayname, displayname); - env->ReleaseStringUTFChars(jusername, username); + if (jdisplayname) env->ReleaseStringUTFChars(jdisplayname, displayname); + if (jusername) env->ReleaseStringUTFChars(jusername, username); } extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContactUsername(JNIEnv* env, jobject thiz, jlong lc) { From 34561b414eaf7de09e40ab86d1aa8f93ad9c233b Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Wed, 2 Apr 2014 13:30:13 +0200 Subject: [PATCH 388/439] Real early media switch to console. Allow using the real hardware to stream early media. --- console/linphonec.c | 15 ++++++++++++++- coreapi/linphonecore.c | 1 - 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index 4385dbb09..f08c0f94d 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -148,6 +148,7 @@ static char last_in_history[256]; #endif //auto answer (-a) option static bool_t auto_answer=FALSE; +static bool_t real_early_media_sending=FALSE; static bool_t answer_call=FALSE; static bool_t vcap_enabled=FALSE; static bool_t display_enabled=FALSE; @@ -362,10 +363,17 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L linphone_call_enable_camera (call,linphonec_camera_enabled); id=(long)linphone_call_get_user_pointer (call); linphonec_set_caller(from); + linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id); if ( auto_answer) { answer_call=TRUE; + } else if (real_early_media_sending) { + linphonec_out("Sending early media using real hardware\n"); + LinphoneCallParams* callparams = linphone_core_create_default_call_parameters(lc); + linphone_call_params_enable_early_media_sending(callparams, TRUE); + if (vcap_enabled) linphone_call_params_enable_video(callparams, TRUE); + linphone_core_accept_early_media_with_params(lc, call, callparams); + linphone_call_params_destroy(callparams); } - linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id); break; case LinphoneCallOutgoingInit: linphonec_call_identify(call); @@ -906,6 +914,7 @@ print_usage (int exit_status) " -l logfile specify the log file for your SIP phone\n" " -s sipaddress specify the sip call to do at startup\n" " -a enable auto answering for incoming calls\n" +" --real-early-media enable sending early media using real audio/video (beware of privacy issue)\n" " -V enable video features globally (disabled by default)\n" " -C enable video capture only (disabled by default)\n" " -D enable video display only (disabled by default)\n" @@ -1229,6 +1238,10 @@ linphonec_parse_cmdline(int argc, char **argv) { auto_answer = TRUE; } + else if (strncmp ("--real-early-media", argv[arg_num], 2) == 0) + { + real_early_media_sending = TRUE; + } else if (strncmp ("-C", argv[arg_num], 2) == 0) { vcap_enabled = TRUE; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index fa94234a1..ce09625ce 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3038,7 +3038,6 @@ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* // if parameters are passed, update the media description if ( params ) { - md = sal_call_get_remote_media_description ( call->op ); _linphone_call_params_copy ( &call->params,params ); linphone_call_make_local_media_description ( lc,call ); sal_call_set_local_media_description ( call->op,call->localdesc ); From 0aaac5f6058e45dd5ffbadd9572d0d1f32ad2741 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Wed, 2 Apr 2014 13:47:00 +0200 Subject: [PATCH 389/439] Coma separated list of user defined alsa devices Config alsadev; patch from Ingo Krabbe. --- coreapi/linphonecore.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ce09625ce..cad98f51e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -536,8 +536,25 @@ static void sound_config_read(LinphoneCore *lc) /*alsadev let the user use custom alsa device within linphone*/ devid=lp_config_get_string(lc->config,"sound","alsadev",NULL); if (devid){ - MSSndCard *card=ms_alsa_card_new_custom(devid,devid); - ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); + MSSndCard* card; + const char* delim=","; + size_t l=strlen(devid); + char* d=malloc(l+1); + char* i; + memcpy(d,devid,l+1); + for (l=0,i=strpbrk(d+l,delim);i;i=strpbrk(d+l,delim)){ + char s=*i; + *i='\0'; + card=ms_alsa_card_new_custom(d+l,d+l); + ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); + *i=s; + l=i-d+1; + } + if(d[l]!='\0') { + card=ms_alsa_card_new_custom(d+l,d+l); + ms_snd_card_manager_add_card(ms_snd_card_manager_get(),card); + } + free(d); } tmp=lp_config_get_int(lc->config,"sound","alsa_forced_rate",-1); if (tmp>0) ms_alsa_card_set_forced_sample_rate(tmp); From 75529783cfff97abcc5bb2eda2535a935bf14d7d Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 2 Apr 2014 17:24:49 +0200 Subject: [PATCH 390/439] bzrtp integration for android --- build/android/Android.mk | 7 +++---- java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java | 4 ---- oRTP | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index f009cf295..c2b04b389 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -199,13 +199,12 @@ LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES) LOCAL_CFLAGS += $(LIBLINPHONE_EXTENDED_CFLAGS) -ifeq ($(BUILD_GPLV3_ZRTP),1) - LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone - LOCAL_SHARED_LIBRARIES += libbzrtp +ifeq ($(BUILD_ZRTP),1) + LOCAL_STATIC_LIBRARIES += libbzrtp endif ifeq ($(BUILD_SRTP),1) - LOCAL_SHARED_LIBRARIES += libsrtp + LOCAL_STATIC_LIBRARIES += libsrtp endif ifeq ($(BUILD_SQLITE),1) diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 8b1527b09..85bff8ffa 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -57,10 +57,6 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { loadOptionalLibrary("avcodec-linphone-arm"); } - // Secure RTP and key negotiation - loadOptionalLibrary("srtp-" + eabi); - loadOptionalLibrary("zrtpcpp-" + eabi); // GPLv3+ - //Main library System.loadLibrary("linphone-" + eabi); diff --git a/oRTP b/oRTP index 5008a70e0..393857c0e 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 5008a70e077b3706de4a48374f162f93071b4d08 +Subproject commit 393857c0e8e5cab10a8d647cc89c8390355745a7 From 274d50168e63f8071250d8abf4f6a32fac86ef6e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 2 Apr 2014 22:23:04 +0200 Subject: [PATCH 391/439] implement digest authentication for anonymous calls (with id privacy) --- coreapi/bellesip_sal/sal_impl.c | 8 +++- coreapi/bellesip_sal/sal_op_impl.c | 9 ++++- tester/call_tester.c | 60 ++++++++++++++++++++++++++++++ tester/flexisip.conf | 2 +- 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index c0340e56a..e4d72e834 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -115,7 +115,13 @@ void sal_process_authentication(SalOp *op) { belle_sip_list_t* auth_list=NULL; belle_sip_auth_event_t* auth_event; belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction); + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(initial_request,belle_sip_header_from_t); + belle_sip_uri_t *from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from); + if (strcasecmp(belle_sip_uri_get_host(from_uri),"anonymous.invalid")==0){ + /*prefer using the from from the SalOp*/ + from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)sal_op_get_from_address(op)); + } if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) { new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request); @@ -132,7 +138,7 @@ void sal_process_authentication(SalOp *op) { return; } - if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,&auth_list)) { + if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,from_uri,&auth_list)) { if (is_within_dialog) { sal_op_send_request(op,new_request); } else { diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 3e5ebe2a5..a6020791e 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -90,18 +90,23 @@ SalAuthInfo * sal_op_get_auth_requested(SalOp *op){ belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ belle_sip_header_contact_t* contact_header; belle_sip_uri_t* contact_uri; + if (sal_op_get_contact_address(op)) { contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op))); } else { contact_header= belle_sip_header_contact_new(); } + if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) { /*no uri, just creating a new one*/ contact_uri=belle_sip_uri_new(); belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri); } + belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op)); - + if (op->privacy!=SalPrivacyNone){ + belle_sip_uri_set_user(contact_uri,NULL); + } belle_sip_header_contact_set_automatic(contact_header,op->base.root->auto_contacts); if (op->base.root->uuid){ if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ @@ -299,7 +304,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { /*hmm just in case we already have authentication param in cache*/ - belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL); + belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL); } result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/); diff --git a/tester/call_tester.c b/tester/call_tester.c index ed44faa9e..419def8cc 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -886,6 +886,65 @@ static void call_with_privacy(void) { linphone_core_manager_destroy(pauline); } +/*this ones makes call with privacy without previous registration*/ +static void call_with_privacy2(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new2( "pauline_rc",FALSE); + LinphoneCall *c1,*c2; + LinphoneCallParams *params; + LinphoneProxyConfig* pauline_proxy; + params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_set_privacy(params,LinphonePrivacyId); + + linphone_core_get_default_proxy(pauline->lc,&pauline_proxy); + linphone_proxy_config_edit(pauline_proxy); + linphone_proxy_config_enable_register(pauline_proxy,FALSE); + linphone_proxy_config_done(pauline_proxy); + + CU_ASSERT_TRUE(call_with_caller_params(pauline,marie,params)); + linphone_call_params_destroy(params); + + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + /*make sure local identity is unchanged*/ + CU_ASSERT_TRUE(linphone_address_weak_equal(linphone_call_log_get_from(linphone_call_get_call_log(c1)),pauline->identity)); + + /*make sure remote identity is hidden*/ + CU_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + CU_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + /*test proxy config privacy*/ + linphone_proxy_config_set_privacy(pauline_proxy,LinphonePrivacyId); + + CU_ASSERT_TRUE(call(pauline,marie)); + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + /*make sure remote identity is hidden*/ + CU_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + CU_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,2)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -1801,6 +1860,7 @@ test_t call_tests[] = { { "SRTP ice call", srtp_ice_call }, #endif { "Call with privacy", call_with_privacy }, + { "Call with privacy 2", call_with_privacy2 }, { "Call rejected because of wrong credential", call_rejected_because_wrong_credentials}, { "Call rejected without 403 because of wrong credential", call_rejected_without_403_because_wrong_credentials}, { "Call rejected without 403 because of wrong credential and no auth req cb", call_rejected_without_403_because_wrong_credentials_no_auth_req_cb}, diff --git a/tester/flexisip.conf b/tester/flexisip.conf index a5cac58fc..48f4a054b 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -128,7 +128,7 @@ no-403=user-agent contains 'tester-no-403' # in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') # && (user-agent == 'Linphone v2') # Default value: -filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains 'auth.example.org' || from.uri.domain contains 'auth1.example.org' || from.uri.domain contains 'auth2.example.org' +filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains 'auth.example.org' || from.uri.domain contains 'auth1.example.org' || from.uri.domain contains 'auth2.example.org' || from.uri.domain contains 'anonymous.invalid' # List of whitespace separated domain names to challenge. Others # are denied. From 5bd12799c70ae7684b229318afec22f9a48d0a57 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 3 Apr 2014 10:12:02 +0200 Subject: [PATCH 392/439] Update mediastreamer2 to enable HD on more devices --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index c3593dcba..90026398a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c3593dcba131ae28837f10d9f01c0500f1ebffe9 +Subproject commit 90026398ae7463ffc8ec0d5538905310cce51f5e From ef08558c02133f376e952a702c9ff46fd634ebda Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Fri, 4 Apr 2014 11:30:03 +0200 Subject: [PATCH 393/439] Update README rpm --- build/redhat/README | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build/redhat/README b/build/redhat/README index 7831df9c8..a38bc3143 100644 --- a/build/redhat/README +++ b/build/redhat/README @@ -16,13 +16,16 @@ Download and install the repo rpmforge : $ sudo yum install ffmpeg-devel $ sudo yum install openldap-devel +- Install antlr3 + $ git clone git://git.linphone.org/antlr3.git + $ cd antlr3 + $ sudo cp antlr-3.4-complete.jar /usr/share/java/antlr3.jar + - Download and install packages $ sudo rpm -Uhv ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-1.3.2-1.el6.x86_64.rpm $ sudo rpm -Uvh ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-devel-1.3.2-1.el6.x86_64.rpm $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-3.2-14.fc15.x86_64.rpm $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-devel-3.2-14.fc15.x86_64.rpm - $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-tool-3.2-14.fc15.noarch.rpm - $ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Fedora/i386/os/Packages/antlr3-java-3.2-14.fc15.noarch.rpm - Git repository @@ -41,6 +44,9 @@ Download and install the repo rpmforge : $ ./configure $ make && make rpm +- Compile msx264 + $ ./autogen.sh && ./configure && make + $ make rpm -Create yum repo : $ cd rpmbuild/RPMS/*arch*/ From e42d96d797634afe73c53adb9588e4c4ccc235d4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 4 Apr 2014 11:43:57 +0200 Subject: [PATCH 394/439] update ms2 (audiomixer bugfix) --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 90026398a..449077d8a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 90026398ae7463ffc8ec0d5538905310cce51f5e +Subproject commit 449077d8af498c6d91a6dde236fd07e5a7f74b03 From 248bc24ab8869680700e3c482936ee2a5fffed7a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 4 Apr 2014 12:36:28 +0200 Subject: [PATCH 395/439] update ms1 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 449077d8a..a33899b52 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 449077d8af498c6d91a6dde236fd07e5a7f74b03 +Subproject commit a33899b52d15236fe99b5399242ab9d8c2a0f24e From 9b4197fef965a5994071dbbdada5865d3fa9fa9b Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 5 Apr 2014 09:45:06 +0200 Subject: [PATCH 396/439] add retry algo for vfu request + enable opus cbr by default --- coreapi/bellesip_sal/sal_op_call.c | 19 +++++++++++++++++-- coreapi/linphonecore.c | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index a77acafd0..e6262c60a 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -168,7 +168,12 @@ static void cancelling_invite(SalOp* op ){ sal_op_send_request(op,cancel); op->state=SalOpStateTerminating; } - +static int vfu_retry (void *user_data, unsigned int events) { + SalOp *op=(SalOp *)user_data; + sal_call_send_vfu_request(op); + sal_op_unref(op); + return BELLE_SIP_STOP; +} static void call_process_response(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; belle_sip_request_t* ack; @@ -177,6 +182,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_ belle_sip_request_t* req; belle_sip_response_t* response=belle_sip_response_event_get_response(event); int code = belle_sip_response_get_status_code(response); + belle_sip_header_content_type_t *header_content_type=NULL; if (!client_transaction) { @@ -247,7 +253,16 @@ static void call_process_response(void *op_base, const belle_sip_response_event_ op->state=SalOpStateActive; } else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){ call_set_error(op,response); - } else { + } else if (code == 491 + && strcmp("INFO",belle_sip_request_get_method(req)) == 0 + && (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t)) + && strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0 + && strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) { + unsigned int retry_in =1000*((float)rand()/RAND_MAX); + belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry"); + ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in); + belle_sip_object_unref(s); + }else { /*ignoring*/ } break; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index cad98f51e..8fccd7561 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1369,7 +1369,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab 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,"useinbandfec=1; usedtx=1"); + linphone_core_assign_payload_type(lc,&payload_type_opus,-1,"useinbandfec=1; usedtx=0; cbr=1"); linphone_core_assign_payload_type(lc,&payload_type_isac,-1,NULL); linphone_core_handle_static_payloads(lc); From 5e01d28d2bb5388a82de982fa274ba1e9f843ef1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 7 Apr 2014 11:57:59 +0200 Subject: [PATCH 397/439] Added linphonecore stop ringing JNI wrapper --- coreapi/linphonecore_jni.cc | 4 ++++ java/common/org/linphone/core/LinphoneCore.java | 5 +++++ java/impl/org/linphone/core/LinphoneCoreImpl.java | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index f5cc41bb9..f7c8f46eb 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -798,6 +798,10 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCallImpl_sendInfoMessage(J return linphone_call_send_info_message((LinphoneCall*)callptr,(LinphoneInfoMessage*)infoptr); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_stopRinging(JNIEnv* env, jobject thiz, jlong lc) { + linphone_core_stop_ringing((LinphoneCore*)lc); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setChatDatabasePath(JNIEnv* env, jobject thiz, jlong lc, jstring jpath) { const char* path = env->GetStringUTFChars(jpath, NULL); linphone_core_set_chat_database_path((LinphoneCore*)lc, path); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 72164a3fe..3d22e10ba 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1585,4 +1585,9 @@ public interface LinphoneCore { **/ public boolean chatEnabled(); + /** + * Whenever the liblinphone is playing a ring to advertise an incoming call or ringback of an outgoing call, this function stops the ringing. + * Typical use is to stop ringing when the user requests to ignore the call. + **/ + public void stopRinging(); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 16ca38e36..7a28a0867 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -149,6 +149,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setCallErrorTone(long nativePtr, int reason, String path); private native void enableSdp200Ack(long nativePtr,boolean enable); private native boolean isSdp200AckEnabled(long nativePtr); + private native void stopRinging(long nativePtr); LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata) throws IOException { mListener = listener; @@ -1181,4 +1182,9 @@ class LinphoneCoreImpl implements LinphoneCore { return chatEnabled(nativePtr); } + @Override + public void stopRinging() { + stopRinging(nativePtr); + } + } From 90b51017647087cc3fb1656a8c933bec5623934b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 7 Apr 2014 12:48:00 +0200 Subject: [PATCH 398/439] Changes to add support of OpenH264 on Android. --- build/android/Android.mk | 8 ++++++++ coreapi/linphonecore_jni.cc | 10 ++++++++++ mediastreamer2 | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index c2b04b389..18fbbdbfd 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -87,6 +87,9 @@ LOCAL_CFLAGS += -DVIDEO_ENABLED ifeq ($(BUILD_X264),1) LOCAL_CFLAGS += -DHAVE_X264 endif +ifeq ($(BUILD_OPENH264),1) +LOCAL_CFLAGS += -DHAVE_OPENH264 +endif endif ifeq ($(BUILD_CONTACT_HEADER),1) @@ -175,6 +178,11 @@ LOCAL_STATIC_LIBRARIES += \ libmsx264 \ libx264 endif +ifeq ($(BUILD_OPENH264),1) +LOCAL_STATIC_LIBRARIES += \ + libmsopenh264 \ + libwels +endif endif ifeq ($(BUILD_UPNP),1) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index f7c8f46eb..824852418 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern "C" { #include "mediastreamer2/mediastream.h" +#include "mediastreamer2/mscommon.h" } #include "mediastreamer2/msjava.h" #include "private.h" @@ -39,6 +40,9 @@ extern "C" void libmsilbc_init(); #ifdef HAVE_X264 extern "C" void libmsx264_init(); #endif +#ifdef HAVE_OPENH264 +extern "C" void libmsopenh264_init(); +#endif #ifdef HAVE_AMR extern "C" void libmsamr_init(); #endif @@ -742,12 +746,17 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* const char* factoryConfig = jfactoryConfig?env->GetStringUTFChars(jfactoryConfig, NULL):NULL; LinphoneCoreData* ldata = new LinphoneCoreData(env,thiz,jlistener,juserdata); + ms_init(); // Initialize mediastreamer2 before loading the plugins + #ifdef HAVE_ILBC libmsilbc_init(); // requires an fpu #endif #ifdef HAVE_X264 libmsx264_init(); #endif +#ifdef HAVE_OPENH264 + libmsopenh264_init(); +#endif #ifdef HAVE_AMR libmsamr_init(); #endif @@ -776,6 +785,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env ,jlong lc) { LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc); linphone_core_destroy((LinphoneCore*)lc); + ms_exit(); delete lcData; } diff --git a/mediastreamer2 b/mediastreamer2 index a33899b52..7111661bd 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a33899b52d15236fe99b5399242ab9d8c2a0f24e +Subproject commit 7111661bd810352ed7a4ecc9c30c7754d3006a92 From affd021540f6f0245803105b9e129521f6ff2a62 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 7 Apr 2014 13:43:38 +0200 Subject: [PATCH 399/439] Add the ability to use a file:// protocol for provisioning --- coreapi/remote_provisioning.c | 63 +++++++++++++++++------ tester/rcfiles/marie_remote_localfile2_rc | 11 ++++ tester/rcfiles/marie_remote_localfile_rc | 3 ++ tester/remote_provisioning_tester.c | 43 ++++++++++------ 4 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 tester/rcfiles/marie_remote_localfile2_rc create mode 100644 tester/rcfiles/marie_remote_localfile_rc diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c index 7deb4d5e6..96ee2a6dd 100644 --- a/coreapi/remote_provisioning.c +++ b/coreapi/remote_provisioning.c @@ -52,11 +52,32 @@ static void linphone_remote_provisioning_apply(LinphoneCore *lc, const char *xml } } +static int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path){ + int status = -1; + FILE* f = fopen(file_path, "r"); + + if( f ){ + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + char* provisioning = ms_malloc(fsize + 1); + fread(provisioning, fsize, 1, f); + fclose(f); + linphone_remote_provisioning_apply(lc, provisioning); + status = 0; + } else { + ms_error("Couldn't open file %s for provisioning", file_path); + } + + return status; +} + static void belle_request_process_response_event(void *ctx, const belle_http_response_event_t *event) { LinphoneCore *lc = (LinphoneCore *)ctx; belle_sip_message_t *body = BELLE_SIP_MESSAGE(event->response); const char *message = belle_sip_message_get_body(body); - + if (belle_http_response_get_status_code(event->response) == 200) { linphone_remote_provisioning_apply(lc, message); } else { @@ -80,23 +101,31 @@ static void belle_request_process_auth_requested(void *ctx, belle_sip_auth_event } int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri) { - belle_generic_uri_t *uri=belle_generic_uri_parse(remote_provisioning_uri); - belle_http_request_listener_callbacks_t belle_request_listener = { - belle_request_process_response_event, - belle_request_process_io_error, - belle_request_process_timeout, - belle_request_process_auth_requested - }; - belle_http_request_listener_t *listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc); - belle_http_request_t *request; - - if (uri==NULL) { - belle_sip_error("Invalid provisioning URI [%s]",remote_provisioning_uri); - return -1; + const char* file_path = strstr(remote_provisioning_uri, "file://"); + + if( file_path == remote_provisioning_uri ){ + // We allow for 'local remote-provisioning' in case the file is to be opened from the hard drive + file_path += strlen("file://"); + return linphone_remote_provisioning_load_file(lc, file_path); + } else { + belle_generic_uri_t *uri=belle_generic_uri_parse(remote_provisioning_uri); + belle_http_request_listener_callbacks_t belle_request_listener = { + belle_request_process_response_event, + belle_request_process_io_error, + belle_request_process_timeout, + belle_request_process_auth_requested + }; + belle_http_request_listener_t *listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc); + belle_http_request_t *request; + + if (uri==NULL) { + belle_sip_error("Invalid provisioning URI [%s]",remote_provisioning_uri); + return -1; + } + request=belle_http_request_create("GET",uri, NULL); + belle_http_provider_send_request(lc->http_provider, request, listener); + return 0; } - request=belle_http_request_create("GET",uri, NULL); - belle_http_provider_send_request(lc->http_provider, request, listener); - return 0; } void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char *uri) { diff --git a/tester/rcfiles/marie_remote_localfile2_rc b/tester/rcfiles/marie_remote_localfile2_rc new file mode 100644 index 000000000..d41ca4c8d --- /dev/null +++ b/tester/rcfiles/marie_remote_localfile2_rc @@ -0,0 +1,11 @@ + + +
+ 0 + 1 +
+
+ 1 + 1 +
+
diff --git a/tester/rcfiles/marie_remote_localfile_rc b/tester/rcfiles/marie_remote_localfile_rc new file mode 100644 index 000000000..b2f947607 --- /dev/null +++ b/tester/rcfiles/marie_remote_localfile_rc @@ -0,0 +1,3 @@ +[misc] +config-uri=file://./rcfiles/marie_remote_localfile2_rc + diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index f38ab9a67..99bfbcc6a 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -1,19 +1,19 @@ /* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. + This program is free software: you can 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. + This program is distributed in the hope that 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include @@ -29,9 +29,9 @@ void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState st if (status == LinphoneConfiguringSkipped) { counters->number_of_LinphoneConfiguringSkipped++; } else if (status == LinphoneConfiguringFailed) { - counters->number_of_LinphoneConfiguringFailed++; + counters->number_of_LinphoneConfiguringFailed++; } else if (status == LinphoneConfiguringSuccessful) { - counters->number_of_LinphoneConfiguringSuccessful++; + counters->number_of_LinphoneConfiguringSuccessful++; } } @@ -89,6 +89,18 @@ static void remote_provisioning_default_values(void) { linphone_core_manager_destroy(marie); } +static void remote_provisioning_file(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_localfile_rc", FALSE); + const LpConfig* conf; + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); + + conf = linphone_core_get_config( marie->lc ); + CU_ASSERT_EQUAL( lp_config_get_int(conf,"misc","tester_file_ok", 0), 1 ); + + linphone_core_manager_destroy(marie); +} + + test_t remote_provisioning_tests[] = { { "Remote provisioning skipped", remote_provisioning_skipped }, { "Remote provisioning successful behind http", remote_provisioning_http }, @@ -96,7 +108,8 @@ test_t remote_provisioning_tests[] = { { "Remote provisioning 404 not found", remote_provisioning_not_found }, { "Remote provisioning invalid", remote_provisioning_invalid }, { "Remote provisioning transient successful", remote_provisioning_transient }, - { "Remote provisioning default values", remote_provisioning_default_values } + { "Remote provisioning default values", remote_provisioning_default_values }, + { "Remote provisioning from file", remote_provisioning_file } }; test_suite_t remote_provisioning_test_suite = { From 7bd50e004faa0cb55ff39a477f766c07efb1a7d9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 7 Apr 2014 17:36:51 +0200 Subject: [PATCH 400/439] allow usage of system-choosen random ports. Implies a lot of refactoring in streams management. --- coreapi/callbacks.c | 7 +- coreapi/linphonecall.c | 259 ++++++++++++++++++++--------------------- coreapi/linphonecore.c | 25 ++-- coreapi/misc.c | 25 ++-- coreapi/private.h | 9 +- mediastreamer2 | 2 +- oRTP | 2 +- tester/call_tester.c | 62 +++++++++- tester/stun_tester.c | 4 +- 9 files changed, 230 insertions(+), 165 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cb88095c7..efd17aab6 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -58,14 +58,14 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr; rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr; ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); - rtp_session_set_remote_addr_full(call->audiostream->ms.session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); } #ifdef VIDEO_ENABLED if (call->videostream && new_videodesc) { rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr; rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr; ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); - rtp_session_set_remote_addr_full(call->videostream->ms.session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); } #else (void)new_videodesc; @@ -97,7 +97,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia sal_media_description_ref(new_md); call->expect_media_in_ack=FALSE; call->resultdesc=new_md; - if ((call->audiostream && call->audiostream->ms.ticker) || (call->videostream && call->videostream->ms.ticker)){ + if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){ /* we already started media: check if we really need to restart it*/ if (oldmd){ int md_changed = media_parameters_changed(call, oldmd, new_md); @@ -671,7 +671,6 @@ static void call_failure(SalOp *op){ !linphone_core_is_media_encryption_mandatory(lc)) { int i; ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call); - linphone_call_stop_media_streams(call); if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress || call->state==LinphoneCallOutgoingRinging /*push case*/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e4cac3a33..c5f3ef3f2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -191,13 +191,13 @@ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t if (call->audiostream==NULL){ ms_error("linphone_call_set_authentication_token_verified(): No audio stream"); } - if (call->audiostream->ms.zrtp_context==NULL){ + if (call->audiostream->ms.sessions.zrtp_context==NULL){ ms_error("linphone_call_set_authentication_token_verified(): No zrtp context."); } if (!call->auth_token_verified && verified){ - ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context); + ortp_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context); }else if (call->auth_token_verified && !verified){ - ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context); + ortp_zrtp_sas_reset_verified(call->audiostream->ms.sessions.zrtp_context); } call->auth_token_verified=verified; propagate_encryption_changed(call); @@ -333,8 +333,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * 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)); strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1); - md->streams[0].rtp_port=call->audio_port; - md->streams[0].rtcp_port=call->audio_port+1; + md->streams[0].rtp_port=call->media_ports[0].rtp_port; + md->streams[0].rtcp_port=call->media_ports[0].rtcp_port; md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? SalProtoRtpSavp : SalProtoRtpAvp; md->streams[0].type=SalAudio; @@ -350,8 +350,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * if (call->params.has_video){ md->n_active_streams++; strncpy(md->streams[0].name,"Video",sizeof(md->streams[0].name)-1); - md->streams[1].rtp_port=call->video_port; - md->streams[1].rtcp_port=call->video_port+1; + md->streams[1].rtp_port=call->media_ports[1].rtp_port; + md->streams[1].rtcp_port=call->media_ports[1].rtcp_port; md->streams[1].proto=md->streams[0].proto; md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); @@ -393,34 +393,19 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * } } -static int find_port_offset(LinphoneCore *lc, SalStreamType type){ +static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){ int offset; MSList *elem; int tried_port; int existing_port; bool_t already_used=FALSE; + for(offset=0;offset<100;offset+=2){ - switch (type) { - default: - case SalAudio: - tried_port=linphone_core_get_audio_port (lc)+offset; - break; - case SalVideo: - tried_port=linphone_core_get_video_port (lc)+offset; - break; - } + tried_port=base_port+offset; already_used=FALSE; for(elem=lc->calls;elem!=NULL;elem=elem->next){ LinphoneCall *call=(LinphoneCall*)elem->data; - switch (type) { - default: - case SalAudio: - existing_port = call->audio_port; - break; - case SalVideo: - existing_port = call->video_port; - break; - } + existing_port=call->media_ports[stream_index].rtp_port; if (existing_port==tried_port) { already_used=TRUE; break; @@ -435,37 +420,19 @@ static int find_port_offset(LinphoneCore *lc, SalStreamType type){ return offset; } -static int select_random_port(LinphoneCore *lc, SalStreamType type) { +static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) { MSList *elem; int nb_tries; int tried_port = 0; int existing_port = 0; - int min_port = 0, max_port = 0; bool_t already_used = FALSE; - switch (type) { - default: - case SalAudio: - linphone_core_get_audio_port_range(lc, &min_port, &max_port); - break; - case SalVideo: - linphone_core_get_video_port_range(lc, &min_port, &max_port); - break; - } tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1; if (tried_port < min_port) tried_port = min_port + 2; for (nb_tries = 0; nb_tries < 100; nb_tries++) { for (elem = lc->calls; elem != NULL; elem = elem->next) { LinphoneCall *call = (LinphoneCall *)elem->data; - switch (type) { - default: - case SalAudio: - existing_port = call->audio_port; - break; - case SalVideo: - existing_port = call->video_port; - break; - } + existing_port=call->media_ports[stream_index].rtp_port; if (existing_port == tried_port) { already_used = TRUE; break; @@ -480,8 +447,31 @@ static int select_random_port(LinphoneCore *lc, SalStreamType type) { return tried_port; } -static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ +static void port_config_set_random(LinphoneCall *call, int stream_index){ + call->media_ports[stream_index].rtp_port=-1; + call->media_ports[stream_index].rtcp_port=-1; +} + +static void port_config_set(LinphoneCall *call, int stream_index, int min_port, int max_port){ int port_offset; + if (min_port>0 && max_port>0){ + if (min_port == max_port) { + /* Used fixed RTP audio port. */ + port_offset=find_port_offset(call->core, stream_index, min_port); + if (port_offset==-1) { + port_config_set_random(call, stream_index); + return; + } + call->media_ports[stream_index].rtp_port=min_port+port_offset; + } else { + /* Select random RTP audio port in the specified range. */ + call->media_ports[stream_index].rtp_port = select_random_port(call->core, stream_index, min_port, max_port); + } + call->media_ports[stream_index].rtcp_port=call->media_ports[stream_index].rtp_port+1; + }else port_config_set_random(call,stream_index); +} + +static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ int min_port, max_port; call->magic=linphone_call_magic; @@ -494,25 +484,11 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->camera_enabled=TRUE; linphone_core_get_audio_port_range(call->core, &min_port, &max_port); - if (min_port == max_port) { - /* Used fixed RTP audio port. */ - port_offset=find_port_offset (call->core, SalAudio); - if (port_offset==-1) return; - call->audio_port=linphone_core_get_audio_port(call->core)+port_offset; - } else { - /* Select random RTP audio port in the specified range. */ - call->audio_port = select_random_port(call->core, SalAudio); - } + port_config_set(call,0,min_port,max_port); + linphone_core_get_video_port_range(call->core, &min_port, &max_port); - if (min_port == max_port) { - /* Used fixed RTP video port. */ - port_offset=find_port_offset (call->core, SalVideo); - if (port_offset==-1) return; - call->video_port=linphone_core_get_video_port(call->core)+port_offset; - } else { - /* Select random RTP video port in the specified range. */ - call->video_port = select_random_port(call->core, SalVideo); - } + port_config_set(call,1,min_port,max_port); + linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO); linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO); } @@ -663,20 +639,22 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro // In this case WE chose the media parameters according to policy. call->params.has_video &= linphone_core_media_description_contains_video_stream(md); } - + /*create the ice session now if ICE is required*/ + if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseIce){ + call->ice_session = ice_session_new(); + ice_session_set_role(call->ice_session, IR_Controlled); + } + /*reserve the sockets immediately*/ + linphone_call_init_media_streams(call); switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: - call->ice_session = ice_session_new(); - ice_session_set_role(call->ice_session, IR_Controlled); + /*start ICE gathering*/ linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op)); - if (call->ice_session != NULL) { - linphone_call_init_media_streams(call); - linphone_call_start_media_streams_for_ice_gathering(call); - if (linphone_core_gather_ice_candidates(call->core,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - linphone_call_stop_media_streams_for_ice_gathering(call); - } + linphone_call_start_media_streams_for_ice_gathering(call); + if (linphone_core_gather_ice_candidates(call->core,call)<0) { + /* Ice candidates gathering failed, proceed with the call anyway. */ + linphone_call_delete_ice_session(call); + linphone_call_stop_media_streams_for_ice_gathering(call); } break; case LinphonePolicyUseStun: @@ -688,7 +666,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro 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); @@ -714,6 +691,11 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro static void linphone_call_set_terminated(LinphoneCall *call){ LinphoneCore *lc=call->core; + linphone_call_stop_media_streams(call); + ms_media_stream_sessions_uninit(&call->sessions[0]); + ms_media_stream_sessions_uninit(&call->sessions[1]); + linphone_call_delete_upnp_session(call); + linphone_call_delete_ice_session(call); linphone_core_update_allocated_audio_bandwidth(lc); call->owns_call_log=FALSE; @@ -856,11 +838,6 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const static void linphone_call_destroy(LinphoneCall *obj) { ms_message("Call [%p] freed.",obj); - linphone_call_stop_media_streams(obj); -#ifdef BUILD_UPNP - linphone_call_delete_upnp_session(obj); -#endif //BUILD_UPNP - linphone_call_delete_ice_session(obj); if (obj->op!=NULL) { sal_op_release(obj->op); obj->op=NULL; @@ -1444,17 +1421,31 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin call->nextVideoFrameDecoded._func = cb; call->nextVideoFrameDecoded._user_data = user_data; #ifdef VIDEO_ENABLED - ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); + if (call->videostream && call->videostream->ms.decoder) + ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); #endif } +static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, RtpSession *session){ + call->media_ports[stream_index].rtp_port=rtp_session_get_local_port(session); + call->media_ports[stream_index].rtcp_port=rtp_session_get_local_rtcp_port(session); +} + void linphone_call_init_audio_stream(LinphoneCall *call){ LinphoneCore *lc=call->core; AudioStream *audiostream; int dscp; if (call->audiostream != NULL) return; - call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,call->af==AF_INET6); + if (call->sessions[0].rtp_session==NULL){ + call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6); + }else{ + call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]); + } + audiostream=call->audiostream; + if (call->media_ports[0].rtp_port==-1){ + port_config_set_random_choosed(call,0,audiostream->ms.sessions.rtp_session); + } dscp=linphone_core_get_audio_dscp(lc); if (dscp!=-1) audio_stream_set_dscp(audiostream,dscp); @@ -1486,69 +1477,73 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc)); if (lc->rtptf){ - RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port); - RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1); - rtp_session_set_transports(audiostream->ms.session,artp,artcp); + RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port); + RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port); + rtp_session_set_transports(audiostream->ms.sessions.rtp_session,artp,artcp); } if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ - rtp_session_set_pktinfo(audiostream->ms.session, TRUE); - rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE); + rtp_session_set_pktinfo(audiostream->ms.sessions.rtp_session, TRUE); + rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session, FALSE); if (ice_session_check_list(call->ice_session, 0) == NULL) { ice_session_add_check_list(call->ice_session, ice_check_list_new()); } audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0); - ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session); + ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.sessions.rtp_session); } call->audiostream_app_evq = ortp_ev_queue_new(); - rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq); + rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); } void linphone_call_init_video_stream(LinphoneCall *call){ #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; - if (!call->params.has_video) { - linphone_call_stop_video_stream(call); - return; - } - if (call->videostream != NULL) return; - if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){ + if (call->videostream == NULL){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); int dscp=linphone_core_get_video_dscp(lc); const char *display_filter=linphone_core_get_video_display_filter(lc); - - call->videostream=video_stream_new(call->video_port,call->video_port+1,call->af==AF_INET6); + + if (call->sessions[1].rtp_session==NULL){ + call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6); + }else{ + call->videostream=video_stream_new_with_sessions(&call->sessions[1]); + } + if (call->media_ports[1].rtp_port==-1){ + port_config_set_random_choosed(call,1,call->videostream->ms.sessions.rtp_session); + } if (dscp!=-1) video_stream_set_dscp(call->videostream,dscp); video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); - if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size); + if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.sessions.rtp_session,video_recv_buf_size); if (display_filter != NULL) video_stream_set_display_filter_name(call->videostream,display_filter); video_stream_set_event_callback(call->videostream,video_stream_event_cb, call); if (lc->rtptf){ - RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port); - RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1); - rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp); + RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port); + RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port); + rtp_session_set_transports(call->videostream->ms.sessions.rtp_session,vrtp,vrtcp); } - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ - rtp_session_set_pktinfo(call->videostream->ms.session, TRUE); - rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE); - if (ice_session_check_list(call->ice_session, 1) == NULL) { - ice_session_add_check_list(call->ice_session, ice_check_list_new()); - } - 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); + call->videostream_app_evq = ortp_ev_queue_new(); + rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); #ifdef TEST_EXT_RENDERER video_stream_set_render_callback(call->videostream,rendercb,NULL); #endif } + /*eventually re-create the ICE check list that may have been destroyed if the stream wasn't used recently*/ + if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ + rtp_session_set_pktinfo(call->videostream->ms.sessions.rtp_session, TRUE); + rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session, FALSE); + if (ice_session_check_list(call->ice_session, 1) == NULL) { + ice_session_add_check_list(call->ice_session, ice_check_list_new()); + } + 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.sessions.rtp_session); + ms_message ("creating new ice video check list [%p] for session [%p]",call->videostream->ms.ice_check_list,call->videostream->ms.sessions.rtp_session); + } + + #else call->videostream=NULL; #endif @@ -1779,9 +1774,9 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca memcpy(¤tconfig, remoteconfig, sizeof(currentconfig)); } if (type == SalAudio) { - session = call->audiostream->ms.session; + session = call->audiostream->ms.sessions.rtp_session; } else { - session = call->videostream->ms.session; + session = call->videostream->ms.sessions.rtp_session; } rtp_session_configure_rtcp_xr(session, ¤tconfig); if (currentconfig.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) { @@ -2166,14 +2161,16 @@ void linphone_call_delete_ice_session(LinphoneCall *call){ } } -#ifdef BUILD_UPNP + void linphone_call_delete_upnp_session(LinphoneCall *call){ +#ifdef BUILD_UPNP if(call->upnp_session!=NULL) { linphone_upnp_session_destroy(call->upnp_session); call->upnp_session=NULL; } -} #endif //BUILD_UPNP +} + static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){ float quality=media_stream_get_average_quality_rating(st); @@ -2186,7 +2183,8 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){ void linphone_call_stop_audio_stream(LinphoneCall *call) { if (call->audiostream!=NULL) { - rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq); + media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[0]); + rtp_session_unregister_event_queue(call->audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); ortp_ev_queue_flush(call->audiostream_app_evq); ortp_ev_queue_destroy(call->audiostream_app_evq); call->audiostream_app_evq=NULL; @@ -2213,7 +2211,8 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) { void linphone_call_stop_video_stream(LinphoneCall *call) { #ifdef VIDEO_ENABLED if (call->videostream!=NULL){ - rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq); + media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[1]); + rtp_session_unregister_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); ortp_ev_queue_flush(call->videostream_app_evq); ortp_ev_queue_destroy(call->videostream_app_evq); call->videostream_app_evq=NULL; @@ -2684,12 +2683,12 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse 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) - audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker); + if (call->audiostream->ms.sessions.ticker) + audio_load=ms_ticker_get_average_load(call->audiostream->ms.sessions.ticker); } if (call->videostream!=NULL){ - if (call->videostream->ms.ticker) - video_load=ms_ticker_get_average_load(call->videostream->ms.ticker); + if (call->videostream->ms.sessions.ticker) + video_load=ms_ticker_get_average_load(call->videostream->ms.sessions.ticker); } report_bandwidth(call,(MediaStream*)call->audiostream,(MediaStream*)call->videostream); ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load); @@ -2716,7 +2715,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted); } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session); + call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.sessions.rtp_session); if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL) freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp); call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet; @@ -2726,7 +2725,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t)); + memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.sessions.rtp_session), sizeof(jitter_stats_t)); if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL) freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp); call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet; @@ -2761,7 +2760,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse } else if (evt == ORTP_EVENT_ZRTP_SAS_READY) { linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified); } else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { - call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session); + call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.sessions.rtp_session); if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL) freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp); call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet; @@ -2771,7 +2770,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { - memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t)); + memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.sessions.rtp_session), sizeof(jitter_stats_t)); if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL) freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp); call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8fccd7561..6c609d037 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1755,6 +1755,8 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc,bool_t rtp_no_ /** * Sets the UDP port used for audio streaming. + * A value if -1 will request the system to allocate the local port randomly. + * This is recommended in order to avoid firewall warnings. * * @ingroup network_parameters **/ @@ -1775,6 +1777,8 @@ void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_ /** * Sets the UDP port used for video streaming. + * A value if -1 will request the system to allocate the local port randomly. + * This is recommended in order to avoid firewall warnings. * * @ingroup network_parameters **/ @@ -2604,6 +2608,10 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){ linphone_call_create_op(call); + linphone_call_stop_media_streams(call); + ms_media_stream_sessions_uninit(&call->sessions[0]); + ms_media_stream_sessions_uninit(&call->sessions[1]); + linphone_call_init_media_streams(call); return linphone_core_start_invite(lc,call, NULL); } @@ -2615,7 +2623,6 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const Linph linphone_call_set_contact_op(call); linphone_core_stop_dtmf_stream(lc); - linphone_call_init_media_streams(call); linphone_call_make_local_media_description(lc,call); if (lc->ringstream==NULL) { @@ -2826,9 +2833,9 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const /* this call becomes now the current one*/ lc->current_call=call; linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); + linphone_call_init_media_streams(call); if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { /* Defer the start of the call after the ICE gathering process. */ - linphone_call_init_media_streams(call); linphone_call_start_media_streams_for_ice_gathering(call); call->log->start_date_time=time(NULL); if (linphone_core_gather_ice_candidates(lc,call)<0) { @@ -2841,7 +2848,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const } else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { #ifdef BUILD_UPNP - linphone_call_init_media_streams(call); call->log->start_date_time=time(NULL); if (linphone_core_update_upnp(lc,call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ @@ -3280,6 +3286,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const } return _linphone_core_accept_call_update(lc, call, params); } + int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ SalMediaDescription *remote_desc; bool_t keep_sdp_version; @@ -3310,13 +3317,13 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons call->params.has_video = FALSE; } call->params.has_video &= linphone_core_media_description_contains_video_stream(remote_desc); + linphone_call_init_media_streams(call); /*so that video stream is initialized if necessary*/ linphone_call_make_local_media_description(lc,call); if (call->ice_session != NULL) { linphone_core_update_ice_from_remote_media_description(call, remote_desc); #ifdef VIDEO_ENABLED - if ((call->ice_session != NULL) &&!ice_session_candidates_gathered(call->ice_session)) { + if ((call->ice_session != NULL) && !ice_session_candidates_gathered(call->ice_session)) { if ((call->params.has_video) && (call->params.has_video != old_has_video)) { - linphone_call_init_video_stream(call); video_stream_prepare_video(call->videostream); if (linphone_core_gather_ice_candidates(lc,call)<0) { /* Ice candidates gathering failed, proceed with the call anyway. */ @@ -3332,7 +3339,6 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); #ifdef VIDEO_ENABLED if ((call->params.has_video) && (call->params.has_video != old_has_video)) { - linphone_call_init_video_stream(call); video_stream_prepare_video(call->videostream); if (linphone_core_update_upnp(lc, call)<0) { /* uPnP update failed, proceed with the call anyway. */ @@ -3435,9 +3441,6 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, sal_op_set_sent_custom_header(call->op,params->custom_headers); } - 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); @@ -3447,7 +3450,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, 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){ + if (!was_ringing && call->audiostream->ms.state==MSStreamInitialized){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } @@ -5366,7 +5369,7 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ } if (file!=NULL) { lc->play_file=ms_strdup(file); - if (call && call->audiostream && call->audiostream->ms.ticker) + if (call && call->audiostream && call->audiostream->ms.state==MSStreamStarted) audio_stream_play(call->audiostream,file); } } diff --git a/coreapi/misc.c b/coreapi/misc.c index 4c9834053..37198490e 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -375,6 +375,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ ms_warning("stun support is not implemented for ipv6"); return -1; } + if (call->media_ports[0].rtp_port==-1){ + ms_warning("Stun-only support not available for system random port"); + return -1; + } if (server!=NULL){ const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc); ortp_socket_t sock1=-1, sock2=-1; @@ -394,10 +398,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ lc->vtable.display_status(lc,_("Stun lookup in progress...")); /*create the two audio and video RTP sockets, and send STUN message to our stun server */ - sock1=create_socket(call->audio_port); + sock1=create_socket(call->media_ports[0].rtp_port); if (sock1==-1) return -1; if (video_enabled){ - sock2=create_socket(call->video_port); + sock2=create_socket(call->media_ports[1].rtp_port); if (sock2==-1) return -1; } got_audio=FALSE; @@ -581,14 +585,14 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) return -1; } if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) { - ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL); - ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL); + ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtp_port, 1, NULL); + ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtcp_port, 2, NULL); call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; } - if (call->params.has_video && (video_check_list != NULL) + if (linphone_core_video_enabled(lc) && (video_check_list != NULL) && (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) { - ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL); - ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL); + ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtp_port, 1, NULL); + ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtcp_port, 2, NULL); call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; } @@ -883,7 +887,12 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } } for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) { - ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1)); + IceCheckList *removed=ice_session_check_list(call->ice_session, i - 1); + ice_session_remove_check_list(call->ice_session, removed); + if (call->audiostream && call->audiostream->ms.ice_check_list==removed) + call->audiostream->ms.ice_check_list=NULL; + if (call->videostream && call->videostream->ms.ice_check_list==removed) + call->videostream->ms.ice_check_list=NULL; } ice_session_check_mismatch(call->ice_session); } else { diff --git a/coreapi/private.h b/coreapi/private.h index 6f421e95e..9fa89dd3a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -155,6 +155,11 @@ typedef struct StunCandidate{ }StunCandidate; +typedef struct _PortConfig{ + int rtp_port; + int rtcp_port; +}PortConfig; + struct _LinphoneCall { int magic; /*used to distinguish from proxy config*/ @@ -178,8 +183,8 @@ struct _LinphoneCall LinphoneProxyConfig *dest_proxy; int refcnt; void * user_pointer; - int audio_port; - int video_port; + PortConfig media_ports[2]; + MSMediaStreamSessions sessions[2]; /*the rtp, srtp, zrtp contexts for each stream*/ StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/ struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; diff --git a/mediastreamer2 b/mediastreamer2 index 7111661bd..da5d1de60 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7111661bd810352ed7a4ecc9c30c7754d3006a92 +Subproject commit da5d1de606699162f48751f006d9219321069545 diff --git a/oRTP b/oRTP index 393857c0e..5008a70e0 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 393857c0e8e5cab10a8d647cc89c8390355745a7 +Subproject commit 5008a70e077b3706de4a48374f162f93071b4d08 diff --git a/tester/call_tester.c b/tester/call_tester.c index 419def8cc..be60fd8af 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -519,7 +519,7 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee return success; } -static void call_with_ice(void) { +static void _call_with_ice(bool_t random_ports) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -527,6 +527,13 @@ static void call_with_ice(void) { 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"); + + if (random_ports){ + linphone_core_set_audio_port(marie->lc,-1); + linphone_core_set_video_port(marie->lc,-1); + linphone_core_set_audio_port(pauline->lc,-1); + linphone_core_set_video_port(pauline->lc,-1); + } CU_ASSERT_TRUE(call(pauline,marie)); @@ -536,8 +543,6 @@ static void call_with_ice(void) { CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); liblinphone_tester_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)); @@ -547,6 +552,14 @@ static void call_with_ice(void) { linphone_core_manager_destroy(pauline); } +static void call_with_ice(void){ + _call_with_ice(FALSE); +} + +static void call_with_ice_random_ports(void){ + _call_with_ice(TRUE); +} + static void call_with_custom_headers(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -718,6 +731,7 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) return wait_for(caller->lc,callee->lc,&callee->stat.number_of_IframeDecoded,initial_callee_stat.number_of_IframeDecoded+1); } else return 0; } + static void call_with_video_added(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -733,7 +747,26 @@ static void call_with_video_added(void) { linphone_core_manager_destroy(pauline); } +static void call_with_video_added_random_ports(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + linphone_core_set_audio_port(marie->lc,-1); + linphone_core_set_video_port(marie->lc,-1); + linphone_core_set_audio_port(pauline->lc,-1); + linphone_core_set_video_port(pauline->lc,-1); + + CU_ASSERT_TRUE(call(pauline,marie)); + CU_ASSERT_TRUE(add_video(pauline,marie)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} static void call_with_declined_video(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -808,19 +841,26 @@ static void video_call(void) { } #endif /*VIDEO_ENABLED*/ -static void call_with_media_relay(void) { +static void _call_with_media_relay(bool_t random_ports) { 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); + + if (random_ports){ + linphone_core_set_audio_port(marie->lc,-1); + linphone_core_set_video_port(marie->lc,-1); + linphone_core_set_audio_port(pauline->lc,-1); + linphone_core_set_video_port(pauline->lc,-1); + } + CU_ASSERT_TRUE(call(pauline,marie)); liblinphone_tester_check_rtcp(pauline,marie); - + #ifdef VIDEO_ENABLED CU_ASSERT_TRUE(add_video(pauline,marie)); liblinphone_tester_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)); @@ -828,7 +868,14 @@ static void call_with_media_relay(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); +} +static void call_with_media_relay(void) { + _call_with_media_relay(FALSE); +} + +static void call_with_media_relay_random_ports(void) { + _call_with_media_relay(TRUE); } static void call_with_privacy(void) { @@ -1839,6 +1886,7 @@ test_t call_tests[] = { { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call", simple_call }, { "Call with media relay", call_with_media_relay}, + { "Call with media relay (random ports)", call_with_media_relay_random_ports}, { "Simple call compatibility mode", simple_call_compatibility_mode }, { "Early-media call", early_media_call }, { "Early-media call with ringing", early_media_call_with_ringing }, @@ -1855,6 +1903,7 @@ test_t call_tests[] = { { "Simple video call",video_call}, { "SRTP ice video call", srtp_video_ice_call }, { "Call with video added", call_with_video_added }, + { "Call with video added (random ports)", call_with_video_added_random_ports }, { "Call with video declined",call_with_declined_video}, #else { "SRTP ice call", srtp_ice_call }, @@ -1872,6 +1921,7 @@ 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 ICE (random ports)", call_with_ice_random_ports }, { "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}, diff --git a/tester/stun_tester.c b/tester/stun_tester.c index e416fa02c..d19650f06 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -73,8 +73,8 @@ static void linphone_stun_test_grab_ip() int tmp=0; memset(&dummy_call, 0, sizeof(LinphoneCall)); - dummy_call.audio_port = 7078; - dummy_call.audio_port = 9078; + dummy_call.media_ports[0].rtp_port = 7078; + dummy_call.media_ports[1].rtp_port = 9078; linphone_core_set_stun_server(lc_stun->lc, stun_address); CU_ASSERT_STRING_EQUAL(stun_address, linphone_core_get_stun_server(lc_stun->lc)); From 0c68cdcfbae933c0d6895f05733069cf37f2c547 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 8 Apr 2014 16:45:23 +0200 Subject: [PATCH 401/439] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index da5d1de60..e51c106c7 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit da5d1de606699162f48751f006d9219321069545 +Subproject commit e51c106c7e48cfc961fbd74b5c8d5a0588a21080 From a8176a398de76f82fd4938e235360b26d68efaa3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 8 Apr 2014 23:38:07 +0200 Subject: [PATCH 402/439] rework SRTP support so that recv and send key can be set and updated independently. --- configure.ac | 64 +++++++++++++++-------------- coreapi/bellesip_sal/sal_sdp.c | 30 +++++++++----- coreapi/linphonecall.c | 74 +++++++++++++++++----------------- coreapi/linphonecore.c | 5 ++- coreapi/remote_provisioning.c | 11 +++-- include/sal/sal.h | 4 +- mediastreamer2 | 2 +- oRTP | 2 +- tester/call_tester.c | 8 ++-- tester/message_tester.c | 4 +- 10 files changed, 112 insertions(+), 92 deletions(-) diff --git a/configure.ac b/configure.ac index 786cb6287..ba4ae31a0 100644 --- a/configure.ac +++ b/configure.ac @@ -680,6 +680,39 @@ AC_SUBST(STRICT_OPTIONS) top_srcdir=`dirname $0` +AC_ARG_ENABLE(external-ortp, + [AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])], + [case "${enableval}" in + yes) external_ortp=true ;; + no) external_ortp=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-external-ortp) ;; + esac], + [external_ortp=false] +) + +if test "$external_ortp" = 'true'; then + PKG_CHECK_MODULES([ORTP], [ortp >= 0.23.0]) + ORTP_VERSION=`$PKG_CONFIG --modversion ortp` +else + AC_CONFIG_SUBDIRS( oRTP ) + ORTP_CFLAGS="-I\$(top_srcdir)/oRTP/include" + ORTP_LIBS="\$(top_builddir)/oRTP/src/libortp.la" + if test x$ac_cv_c_bigendian = xyes ; then + ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN" + fi + if test x$ntptimestamp = xtrue ; then + ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_TIMESTAMP" + fi + ORTP_DIR=oRTP + changequote(<<, >>) + ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'` + changequote([, ]) +fi +AC_SUBST(ORTP_CFLAGS) +AC_SUBST(ORTP_LIBS) +AC_SUBST([ORTP_VERSION]) +AC_SUBST([ORTP_DIR]) + AC_ARG_ENABLE([external-mediastreamer], [AS_HELP_STRING([--enable-external-mediastreamer],[Use external mediastreamer library])],, [enable_external_mediastreamer=no] @@ -778,38 +811,7 @@ AC_DEFINE_UNQUOTED(LINPHONE_PLUGINS_DIR, "${package_prefix}/lib/liblinphone/plug LINPHONE_PLUGINS_DIR="${package_prefix}/lib/liblinphone/plugins" AC_SUBST(LINPHONE_PLUGINS_DIR) -AC_ARG_ENABLE(external-ortp, - [AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])], - [case "${enableval}" in - yes) external_ortp=true ;; - no) external_ortp=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-external-ortp) ;; - esac], - [external_ortp=false] -) -if test "$external_ortp" = 'true'; then - PKG_CHECK_MODULES([ORTP], [ortp >= 0.23.0]) - ORTP_VERSION=`$PKG_CONFIG --modversion ortp` -else - AC_CONFIG_SUBDIRS( oRTP ) - ORTP_CFLAGS="-I\$(top_srcdir)/oRTP/include" - ORTP_LIBS="\$(top_builddir)/oRTP/src/libortp.la" - if test x$ac_cv_c_bigendian = xyes ; then - ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN" - fi - if test x$ntptimestamp = xtrue ; then - ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_TIMESTAMP" - fi - ORTP_DIR=oRTP - changequote(<<, >>) - ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'` - changequote([, ]) -fi -AC_SUBST(ORTP_CFLAGS) -AC_SUBST(ORTP_LIBS) -AC_SUBST([ORTP_VERSION]) -AC_SUBST([ORTP_DIR]) AC_ARG_ENABLE(tutorials, [AS_HELP_STRING([--disable-tutorials], [Disable compilation of tutorials])], diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index b2f106cef..2c9411841 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -146,17 +146,20 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session if ( stream->proto == SalProtoRtpSavp ) { /* add crypto lines */ for ( j=0; jcrypto[j].algo ) { case AES_128_SHA1_80: - snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s", - stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", stream->crypto[j].master_key ); - belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) ); + enc_name="AES_CM_128_HMAC_SHA1_80"; break; case AES_128_SHA1_32: - snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s", - stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", stream->crypto[j].master_key ); - belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) ); + enc_name="AES_CM_128_HMAC_SHA1_32"; + break; + case AES_256_SHA1_32: + enc_name="AES_CM_256_HMAC_SHA1_32"; + break; + case AES_256_SHA1_80: + enc_name="AES_CM_256_HMAC_SHA1_32"; break; case AES_128_NO_AUTH: ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" ); @@ -168,6 +171,11 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session j = SAL_CRYPTO_ALGO_MAX; /* no break */ } + if (enc_name){ + snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s", + stream->crypto[j].tag, enc_name, stream->crypto[j].master_key ); + belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) ); + } } } switch ( stream->dir ) { @@ -342,11 +350,15 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med tmp, tmp2 ); if ( nb == 3 ) { - if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ) + 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 { + }else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_32",tmp ) == 0 ){ + stream->crypto[valid_count].algo = AES_256_SHA1_32; + }else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_80",tmp ) == 0 ){ + stream->crypto[valid_count].algo = AES_256_SHA1_80; + }else { ms_warning ( "Failed to parse crypto-algo: '%s'", tmp ); stream->crypto[valid_count].algo = 0; } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c5f3ef3f2..cf69902c7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1873,11 +1873,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); if (crypto_idx >= 0) { - audio_stream_enable_srtp( - call->audiostream, - stream->crypto[0].algo, - local_st_desc->crypto[crypto_idx].master_key, - stream->crypto[0].master_key); + media_stream_set_srtp_recv_key(&call->audiostream->ms,stream->crypto[0].algo,stream->crypto[0].master_key); + media_stream_set_srtp_send_key(&call->audiostream->ms,stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); call->audiostream_encrypted=TRUE; } else { ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); @@ -1996,13 +1993,13 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna } if (!is_inactive){ if (vstream->proto == SalProtoRtpSavp) { - video_stream_enable_strp( - call->videostream, - vstream->crypto[0].algo, - local_st_desc->crypto[0].master_key, - vstream->crypto[0].master_key - ); - call->videostream_encrypted=TRUE; + int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag); + + if (crypto_idx >= 0) { + media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key); + media_stream_set_srtp_send_key(&call->videostream->ms,vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); + call->videostream_encrypted=TRUE; + }else call->videostream_encrypted=FALSE; }else{ call->videostream_encrypted=FALSE; } @@ -2103,42 +2100,43 @@ void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ #endif } +static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDescription *local_st_desc, SalStreamDescription *old_stream, SalStreamDescription *new_stream, MediaStream *ms){ + int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); + if (crypto_idx >= 0) { + if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED) + media_stream_set_srtp_send_key(ms,new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); + if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){ + media_stream_set_srtp_recv_key(ms,new_stream->crypto[0].algo,new_stream->crypto[0].master_key); + } + return TRUE; + } else { + ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); + } + return FALSE; +} + void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { SalStreamDescription *old_stream; SalStreamDescription *new_stream; - + const SalStreamDescription *local_st_desc; + + local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio); old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio); new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio); - if (old_stream && new_stream) { - const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio); - if (local_st_desc) { - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); - if (crypto_idx >= 0) { - audio_stream_enable_srtp(call->audiostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key); - call->audiostream_encrypted = TRUE; - } else { - ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); - call->audiostream_encrypted = FALSE; - } - } - } + if (call->audiostream && local_st_desc && old_stream && new_stream && + update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){ + call->audiostream_encrypted = TRUE; + }else call->audiostream_encrypted = FALSE; #ifdef VIDEO_ENABLED + local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo); old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo); new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo); - if (old_stream && new_stream) { - const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo); - if (local_st_desc) { - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); - if (crypto_idx >= 0) { - video_stream_enable_strp(call->videostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key); - call->videostream_encrypted = TRUE; - } else { - ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); - call->videostream_encrypted = FALSE; - } - } + if (call->videostream && local_st_desc && old_stream && new_stream && + update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){ + call->videostream_encrypted = TRUE; } + call->videostream_encrypted = FALSE; #endif } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6c609d037..1ac48dff7 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6380,6 +6380,7 @@ const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){ case LinphoneMediaEncryptionNone: return "LinphoneMediaEncryptionNone"; } + ms_error("Invalid LinphoneMediaEncryption value %i",(int)menc); return "INVALID"; } @@ -6389,7 +6390,7 @@ const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc){ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc){ switch(menc){ case LinphoneMediaEncryptionSRTP: - return ortp_srtp_supported(); + return media_stream_srtp_supported(); case LinphoneMediaEncryptionZRTP: return ortp_zrtp_available(); case LinphoneMediaEncryptionNone: @@ -6402,7 +6403,7 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption const char *type="none"; int ret=0; if (menc == LinphoneMediaEncryptionSRTP){ - if (!ortp_srtp_supported()){ + if (!media_stream_srtp_supported()){ ms_warning("SRTP not supported by library."); type="none"; ret=-1; diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c index 96ee2a6dd..bcae9e798 100644 --- a/coreapi/remote_provisioning.c +++ b/coreapi/remote_provisioning.c @@ -62,10 +62,15 @@ static int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* fseek(f, 0, SEEK_SET); char* provisioning = ms_malloc(fsize + 1); - fread(provisioning, fsize, 1, f); + if (fread(provisioning, fsize, 1, f)==0){ + ms_error("Could not read xml provisioning file from %s",file_path); + status=-1; + }else{ + linphone_remote_provisioning_apply(lc, provisioning); + status = 0; + } + ms_free(provisioning); fclose(f); - linphone_remote_provisioning_apply(lc, provisioning); - status = 0; } else { ms_error("Couldn't open file %s for provisioning", file_path); } diff --git a/include/sal/sal.h b/include/sal/sal.h index 5bc5264a2..1dba31f90 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -166,12 +166,12 @@ typedef struct SalIceRemoteCandidate { #define SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN 256 #define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256 -#define SAL_SRTP_KEY_SIZE 41 +/*sufficient for 256bit keys encoded in base 64*/ +#define SAL_SRTP_KEY_SIZE 64 typedef struct SalSrtpCryptoAlgo { unsigned int tag; enum ortp_srtp_crypto_suite_t algo; - /* 41= 40 max(key_length for all algo) + '\0' */ char master_key[SAL_SRTP_KEY_SIZE]; } SalSrtpCryptoAlgo; diff --git a/mediastreamer2 b/mediastreamer2 index e51c106c7..8858dc193 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e51c106c7e48cfc961fbd74b5c8d5a0588a21080 +Subproject commit 8858dc1938b14d2a84773052fa3bc87fd0950800 diff --git a/oRTP b/oRTP index 5008a70e0..daa314ae9 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 5008a70e077b3706de4a48374f162f93071b4d08 +Subproject commit daa314ae9c0ba46910299ebc70301897aea7448f diff --git a/tester/call_tester.c b/tester/call_tester.c index be60fd8af..2a18b30d2 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1155,6 +1155,7 @@ static void encrypted_call(LinphoneMediaEncryption mode) { CU_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) ,linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))); } + liblinphone_tester_check_rtcp(pauline,marie); /*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)); @@ -1165,13 +1166,14 @@ static void encrypted_call(LinphoneMediaEncryption mode) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } -static void srtp_call(LinphoneMediaEncryptionSRTP) { + +static void srtp_call() { encrypted_call(LinphoneMediaEncryptionSRTP); } /* - * futur work -static void zrtp_call(LinphoneMediaEncryptionSRTP) { + * future work +static void zrtp_call() { encrypted_call(LinphoneMediaEncryptionZRTP); }*/ diff --git a/tester/message_tester.c b/tester/message_tester.c index 259727715..8568492d4 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -42,8 +42,8 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess counters = get_stats(lc); counters->number_of_LinphoneMessageReceived++; if (linphone_chat_message_get_external_body_url(message)) { - counters->number_of_LinphoneMessageExtBodyReceived++; - CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); + counters->number_of_LinphoneMessageExtBodyReceived++; + CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); } } From 50c60455cec1576308ff3d321c953bf40e448301 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 8 Apr 2014 23:40:55 +0200 Subject: [PATCH 403/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 8858dc193..fd97e9048 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8858dc1938b14d2a84773052fa3bc87fd0950800 +Subproject commit fd97e9048e2e5f5b8a2dd972d0d7848294742f89 From bd83f0b7ca66bd600cd4646ce40223d00997aa6d Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 9 Apr 2014 00:00:22 +0200 Subject: [PATCH 404/439] fix crash while receiving a SIP message without content-type. --- coreapi/bellesip_sal/sal_op_message.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index c346347d0..2f161c2a6 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -130,8 +130,7 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve belle_sip_object_unref(address); belle_sip_free(from); } else { - ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type) - ,belle_sip_header_content_type_get_subtype(content_type)); + ms_error("Unsupported MESSAGE (content-type not recognized)"); resp = belle_sip_response_create_from_request(req,415); add_message_accept((belle_sip_message_t*)resp); belle_sip_server_transaction_send_response(server_transaction,resp); From 756ae1737a0ed61d4daab94636d4b490d83e2fa7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 9 Apr 2014 11:15:09 +0200 Subject: [PATCH 405/439] fix upnp build --- coreapi/upnp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 7b1307435..741e44529 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -698,19 +698,19 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool * Audio part */ linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp, - UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port:0, UPNP_CALL_RETRY_DELAY); + UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtp_port:0, UPNP_CALL_RETRY_DELAY); linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp, - UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port+1:0, UPNP_CALL_RETRY_DELAY); + UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtcp_port:0, UPNP_CALL_RETRY_DELAY); /* * Video part */ linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp, - UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port:0, UPNP_CALL_RETRY_DELAY); + UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtp_port:0, UPNP_CALL_RETRY_DELAY); linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp, - UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port+1:0, UPNP_CALL_RETRY_DELAY); + UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtcp_port:0, UPNP_CALL_RETRY_DELAY); } ms_mutex_unlock(&lupnp->mutex); From 0868c544d42ba4a7668288f59659ce33c3fffe4f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 9 Apr 2014 16:27:30 +0200 Subject: [PATCH 406/439] fix preview ring bug --- coreapi/linphonecore.c | 14 ++++++++++++-- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1ac48dff7..d6b3f842c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2262,7 +2262,15 @@ 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){ - linphone_core_stop_dtmf_stream(lc); + MSPlayerState state; + bool_t stop=TRUE; + if (lc->ringstream->source && ms_filter_call_method(lc->ringstream->source,MS_PLAYER_GET_STATE,&state)==0){ + if (state==MSPlayerPlaying) stop=FALSE; + } + if (stop) { + ms_message("Releasing inactive tone player."); + linphone_core_stop_dtmf_stream(lc); + } } sal_iterate(lc->sal); @@ -4412,7 +4420,9 @@ void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){ static void notify_end_of_ring(void *ud, MSFilter *f, unsigned int event, void *arg){ LinphoneCore *lc=(LinphoneCore*)ud; - lc->preview_finished=1; + if (event==MS_PLAYER_EOF){ + lc->preview_finished=1; + } } int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata) diff --git a/mediastreamer2 b/mediastreamer2 index fd97e9048..e2a163d31 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit fd97e9048e2e5f5b8a2dd972d0d7848294742f89 +Subproject commit e2a163d31b7e51811dd907a640788c61b24e83b0 diff --git a/oRTP b/oRTP index daa314ae9..550e1e1e4 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit daa314ae9c0ba46910299ebc70301897aea7448f +Subproject commit 550e1e1e43ec64b3be96c34e0adb618f4752f34a From f64c06a85c8aa3e175f594e6e56ba6116f8f2ff8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 9 Apr 2014 16:55:09 +0200 Subject: [PATCH 407/439] fix compilation on mac --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e2a163d31..3053e4fd0 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e2a163d31b7e51811dd907a640788c61b24e83b0 +Subproject commit 3053e4fd0ec6817213576821ec5e3392b8791904 From cc7d32654a91f3dbf776424d3c02d3548ff00c96 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 10 Apr 2014 11:19:27 +0200 Subject: [PATCH 408/439] add bzrtp in windows setup.exe --- linphone-deps.filelist | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/linphone-deps.filelist b/linphone-deps.filelist index fd8e6da17..53cde44a9 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -2,8 +2,6 @@ ./bin/libspeex-1.dll ./bin/libspeexdsp-1.dll ./bin/avutil-51.dll -./bin/libeay32.dll -./bin/ssleay32.dll ./bin/libbellesip-0.dll ./bin/libantlr3c.dll ./lib/libpolarssl.dll @@ -17,5 +15,5 @@ ./bin/libgnutls-26.dll ./bin/libtasn1-3.dll ./bin/libsqlite3-0.dll -./bin/zrtpcppcore.dll ./bin/libopus-0.dll +./bin/libbzrtp-0.dll From 28dc28a244f7ad93f953cc44a537d854a9403858 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 10 Apr 2014 11:31:02 +0200 Subject: [PATCH 409/439] updated ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 3053e4fd0..29b6bbe34 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3053e4fd0ec6817213576821ec5e3392b8791904 +Subproject commit 29b6bbe34100e47573c532bf77f9ce6ba2dc30db From b28472af78f9422db2869c48aaaff619ec48d66e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 10 Apr 2014 16:47:10 +0200 Subject: [PATCH 410/439] Update ms2 and oRTP submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 29b6bbe34..6aa698351 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 29b6bbe34100e47573c532bf77f9ce6ba2dc30db +Subproject commit 6aa6983512e5fa61ccdaaedc79f109993c5de04a diff --git a/oRTP b/oRTP index 550e1e1e4..6330e3d1c 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 550e1e1e43ec64b3be96c34e0adb618f4752f34a +Subproject commit 6330e3d1c792515826be7116fb31086284faa430 From 7aec150bf4f0df7d2a84155687e59aff1eee3aa4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 10 Apr 2014 19:42:42 +0200 Subject: [PATCH 411/439] fix missing custom header processing in generic PUBLISH api --- coreapi/bellesip_sal/sal_op_publish.c | 6 ++++-- coreapi/event.c | 5 ++++- tester/eventapi_tester.c | 16 +++++++++++----- tester/tester.c | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 81a7ce724..0e2ca3da9 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -24,18 +24,20 @@ static void publish_refresher_listener (belle_sip_refresher_t* refresher ,unsigned int status_code ,const char* reason_phrase) { SalOp* op = (SalOp*)user_pointer; + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + belle_sip_response_t *response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(last_publish_trans)); /*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/ ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op)); if (status_code==412){ /*resubmit the request after removing the SIP-If-Match*/ - const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); - belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match"); belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES); }else if (status_code==0){ op->base.root->callbacks.on_expire(op); }else if (status_code>=200){ sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); op->base.root->callbacks.on_publish_response(op); } } diff --git a/coreapi/event.c b/coreapi/event.c index 731412153..28ea5914b 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -234,7 +234,10 @@ static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneConten ms_error("linphone_event_update_publish(): this is not a PUBLISH event."); return -1; } - + if (lev->send_custom_headers){ + sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers); + lev->send_custom_headers=NULL; + }else sal_op_set_sent_custom_header(lev->op,NULL); err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body)); if (err==0){ linphone_event_set_publish_state(lev,LinphonePublishProgress); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index 5f10a5183..9d776fa40 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -97,7 +97,11 @@ void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, Linphon stats* counters = get_stats(lc); switch(state){ case LinphonePublishProgress: counters->number_of_LinphonePublishProgress++; break; - case LinphonePublishOk: counters->number_of_LinphonePublishOk++; break; + case LinphonePublishOk: + /*make sure custom header access API is working*/ + CU_ASSERT_PTR_NOT_NULL(linphone_event_get_custom_header(ev,"From")); + counters->number_of_LinphonePublishOk++; + break; case LinphonePublishError: counters->number_of_LinphonePublishError++; break; case LinphonePublishExpiring: counters->number_of_LinphonePublishExpiring++; break; case LinphonePublishCleared: counters->number_of_LinphonePublishCleared++;break; @@ -300,24 +304,26 @@ static void publish_test_with_args(bool_t refresh){ lp_config_set_int(marie->lc->config,"sip","refresh_generic_publish",refresh); - lev=linphone_core_publish(marie->lc,pauline->identity,"dodo",5,&content); + lev=linphone_core_create_publish(marie->lc,pauline->identity,"dodo",5); + linphone_event_add_custom_header(lev,"CustomHeader","someValue"); + linphone_event_send_publish(lev,&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)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,3000)); 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)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,3000)); }else{ } linphone_event_terminate(lev); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishCleared,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishCleared,1,3000)); linphone_event_unref(lev); diff --git a/tester/tester.c b/tester/tester.c index 9eedb0ed1..caeb78009 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -216,7 +216,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f proxy_count=0; if (proxy_count) - wait_for_until(mgr->lc,NULL,&mgr->stat.number_of_LinphoneRegistrationOk,proxy_count,3000*proxy_count); + wait_for_until(mgr->lc,NULL,&mgr->stat.number_of_LinphoneRegistrationOk,proxy_count,5000*proxy_count); CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count); enable_codec(mgr->lc,"PCMU",8000); From 39f9ec6a48f850b103b558db0a290a8fd9419c3b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 11 Apr 2014 10:00:13 +0200 Subject: [PATCH 412/439] improve LinphoneEvent api: - better error notification - allow publish without expires --- coreapi/bellesip_sal/sal_op_publish.c | 4 +++- coreapi/callbacks.c | 13 ++++++++++--- coreapi/event.c | 2 +- coreapi/event.h | 7 ++++--- .../common/org/linphone/core/SubscriptionState.java | 4 ++-- tester/eventapi_tester.c | 13 +++++++++---- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 0e2ca3da9..2655c58d2 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -106,7 +106,9 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna } belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname)); sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body); - return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); + if (expires!=-1) + return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); + else return sal_op_send_request(op,req); } else { /*update status*/ const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index efd17aab6..2bbea45b2 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -1052,6 +1052,7 @@ static void info_received(SalOp *op, const SalBody *body){ static void subscribe_response(SalOp *op, SalSubscribeStatus status){ LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + const SalErrorInfo *ei=sal_op_get_error_info(op); if (lev==NULL) return; @@ -1060,7 +1061,10 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status){ }else if (status==SalSubscribePending){ linphone_event_set_state(lev,LinphoneSubscriptionPending); }else{ - linphone_event_set_state(lev,LinphoneSubscriptionError); + if (lev->subscription_state==LinphoneSubscriptionActive && ei->reason==SalReasonIOError){ + linphone_event_set_state(lev,LinphoneSubscriptionOutgoingProgress); + } + else linphone_event_set_state(lev,LinphoneSubscriptionError); } } @@ -1111,9 +1115,12 @@ static void on_publish_response(SalOp* op){ linphone_event_set_publish_state(lev,LinphonePublishOk); else linphone_event_set_publish_state(lev,LinphonePublishCleared); - }else{ - linphone_event_set_publish_state(lev,LinphonePublishError); + if (lev->publish_state==LinphonePublishOk){ + linphone_event_set_publish_state(lev,LinphonePublishProgress); + }else{ + linphone_event_set_publish_state(lev,LinphonePublishError); + } } } diff --git a/coreapi/event.c b/coreapi/event.c index 28ea5914b..e95f7d454 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -295,7 +295,7 @@ void linphone_event_terminate(LinphoneEvent *lev){ } if (lev->publish_state!=LinphonePublishNone){ - if (lev->publish_state==LinphonePublishOk){ + if (lev->publish_state==LinphonePublishOk && lev->expires!=-1){ sal_publish(lev->op,NULL,NULL,NULL,0,NULL); }else sal_op_stop_refreshing(lev->op); linphone_event_set_publish_state(lev,LinphonePublishCleared); diff --git a/coreapi/event.h b/coreapi/event.h index 5985d1c96..2b0e2bf0d 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -52,7 +52,7 @@ typedef enum _LinphoneSubscriptionDir LinphoneSubscriptionDir; **/ enum _LinphoneSubscriptionState{ LinphoneSubscriptionNone, /**< Initial state, should not be used.**/ - LinphoneSubscriptionOutgoingInit, /**lc->config,"sip","refresh_generic_publish",refresh); - lev=linphone_core_create_publish(marie->lc,pauline->identity,"dodo",5); + lev=linphone_core_create_publish(marie->lc,pauline->identity,"dodo",expires); linphone_event_add_custom_header(lev,"CustomHeader","someValue"); linphone_event_send_publish(lev,&content); linphone_event_ref(lev); @@ -332,11 +332,15 @@ static void publish_test_with_args(bool_t refresh){ } static void publish_test(){ - publish_test_with_args(TRUE); + publish_test_with_args(TRUE,5); } static void publish_no_auto_test(){ - publish_test_with_args(FALSE); + publish_test_with_args(FALSE,5); +} + +static void publish_without_expires(){ + publish_test_with_args(TRUE,-1); } test_t event_tests[] = { @@ -347,6 +351,7 @@ test_t event_tests[] = { { "Subscribe manually refreshed", subscribe_test_manually_refreshed }, { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier }, { "Publish", publish_test }, + { "Publish without expires", publish_without_expires }, { "Publish without automatic refresh",publish_no_auto_test } }; From 643d39637bb0130d35275fbaaeb0b24d31122345 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 11 Apr 2014 11:10:56 +0200 Subject: [PATCH 413/439] repair android build, serialize proxy configs. --- coreapi/linphonecore_jni.cc | 21 ++++++++++++++++--- .../linphone/core/LinphoneCoreListener.java | 2 +- .../org/linphone/core/LinphoneCoreImpl.java | 8 ++++--- .../core/LinphoneProxyConfigImpl.java | 14 ++++++++++--- mediastreamer2 | 2 +- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 824852418..2b0c79897 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -224,6 +224,8 @@ public: /*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/ newSubscriptionRequestId = env->GetMethodID(listenerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V"); + + authInfoRequestedId = env->GetMethodID(listenerClass,"authInfoRequested","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); /*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/ notifyPresenceReceivedId = env->GetMethodID(listenerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;)V"); @@ -245,7 +247,7 @@ public: proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); - proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); + proxyCtrId = env->GetMethodID(proxyClass,"", "(Lorg/linphone/core/LinphoneCoreImpl;J)V"); callClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallImpl")); callCtrId = env->GetMethodID(callClass,"", "(J)V"); @@ -325,6 +327,7 @@ public: jmethodID transferStateId; jmethodID infoReceivedId; jmethodID subscriptionStateId; + jmethodID authInfoRequestedId; jmethodID publishStateId; jmethodID notifyRecvId; @@ -413,7 +416,19 @@ public: } static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { - + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener, + lcData->authInfoRequestedId, + lcData->core, + realm ? env->NewStringUTF(realm):NULL, + username ? env->NewStringUTF(username) : NULL, + domain ? env->NewStringUTF(domain) : NULL); } static void globalStateChange(LinphoneCore *lc, LinphoneGlobalState gstate,const char* message) { JNIEnv *env = 0; @@ -440,7 +455,7 @@ public: env->CallVoidMethod(lcData->listener ,lcData->registrationStateId ,lcData->core - ,env->NewObject(lcData->proxyClass,lcData->proxyCtrId,(jlong)proxy) + ,env->NewObject(lcData->proxyClass,lcData->proxyCtrId,lcData->core,(jlong)proxy) ,env->CallStaticObjectMethod(lcData->registrationStateClass,lcData->registrationStateFromIntId,(jint)state), message ? env->NewStringUTF(message) : NULL); } diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index 5d2ac5f5f..bd83172a9 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -28,7 +28,7 @@ import org.linphone.core.LinphoneCore.RemoteProvisioningState; public interface LinphoneCoreListener { /**< Ask the application some authentication information * @return */ - void authInfoRequested(LinphoneCore lc,String realm,String username); + void authInfoRequested(LinphoneCore lc, String realm, String username, String Domain); /** General State notification * @param state LinphoneCore.State diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 7a28a0867..66597ca81 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -192,7 +192,7 @@ class LinphoneCoreImpl implements LinphoneCore { isValid(); long lNativePtr = getDefaultProxyConfig(nativePtr); if (lNativePtr!=0) { - return new LinphoneProxyConfigImpl(lNativePtr); + return new LinphoneProxyConfigImpl(this,lNativePtr); } else { return null; } @@ -218,10 +218,12 @@ class LinphoneCoreImpl implements LinphoneCore { if (addProxyConfig(proxyCfg,nativePtr,((LinphoneProxyConfigImpl)proxyCfg).nativePtr) !=0) { throw new LinphoneCoreException("bad proxy config"); } + ((LinphoneProxyConfigImpl)proxyCfg).mCore=this; } public synchronized void removeProxyConfig(LinphoneProxyConfig proxyCfg) { isValid(); removeProxyConfig(nativePtr, ((LinphoneProxyConfigImpl)proxyCfg).nativePtr); + ((LinphoneProxyConfigImpl)proxyCfg).mCore=null; } public synchronized void clearAuthInfos() { isValid(); @@ -517,7 +519,7 @@ class LinphoneCoreImpl implements LinphoneCore { LinphoneProxyConfig[] proxies = new LinphoneProxyConfig[typesPtr.length]; for (int i=0; i < proxies.length; i++) { - proxies[i] = new LinphoneProxyConfigImpl(typesPtr[i]); + proxies[i] = new LinphoneProxyConfigImpl(this,typesPtr[i]); } return proxies; @@ -1137,7 +1139,7 @@ class LinphoneCoreImpl implements LinphoneCore { } @Override public synchronized LinphoneProxyConfig createProxyConfig() { - return new LinphoneProxyConfigImpl(createProxyConfig(nativePtr)); + return new LinphoneProxyConfigImpl(this,createProxyConfig(nativePtr)); } @Override public synchronized void setCallErrorTone(Reason reason, String path) { diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 96b153733..a78819075 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -27,6 +27,7 @@ import org.linphone.core.LinphoneCore.RegistrationState; class LinphoneProxyConfigImpl implements LinphoneProxyConfig { protected final long nativePtr; + protected LinphoneCoreImpl mCore; private native int getState(long nativePtr); private native void setExpires(long nativePtr, int delay); @@ -41,9 +42,10 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { enableRegister(enableRegister); ownPtr=true; } - protected LinphoneProxyConfigImpl(long aNativePtr) { + protected LinphoneProxyConfigImpl(LinphoneCoreImpl core, long aNativePtr) { nativePtr = aNativePtr; ownPtr=false; + mCore=core; } protected void finalize() throws Throwable { //Log.e(LinphoneService.TAG,"fixme, should release underlying proxy config"); @@ -90,11 +92,17 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { } public void done() { - done(nativePtr); + Object mutex=mCore!=null ? mCore : this; + synchronized(mutex){ + done(nativePtr); + } } public LinphoneProxyConfig edit() { - edit(nativePtr); + Object mutex=mCore!=null ? mCore : this; + synchronized(mutex){ + edit(nativePtr); + } return this; } diff --git a/mediastreamer2 b/mediastreamer2 index 6aa698351..b76e3dde1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6aa6983512e5fa61ccdaaedc79f109993c5de04a +Subproject commit b76e3dde111af0d24be4ac5f1d4f633361e654c1 From 5e3ff318d97f2f5eecaa57958858f3b0a91dae87 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 11 Apr 2014 11:51:12 +0200 Subject: [PATCH 414/439] add ref count to LinphoneChatMessage --- coreapi/chat.c | 46 ++++++++++++++++++++++++++++++++++++++---- coreapi/linphonecore.h | 2 ++ coreapi/private.h | 6 +++++- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index ef01b8b11..fe0370afe 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -32,6 +32,18 @@ #define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 #define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120 +static void _linphone_chat_message_destroy(LinphoneChatMessage* msg); + +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage); + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatMessage,belle_sip_object_t, + (belle_sip_object_destroy_t)_linphone_chat_message_destroy, + NULL, // clone + NULL, // marshal + FALSE +); + + /** * @addtogroup chatroom * @{ @@ -406,7 +418,7 @@ const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) * @return a new #LinphoneChatMessage */ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, const char* message) { - LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1); + LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage); msg->chat_room=(LinphoneChatRoom*)cr; msg->message=message?ms_strdup(message):NULL; msg->is_read=TRUE; @@ -429,7 +441,7 @@ LinphoneChatMessage* linphone_chat_room_create_message_2( LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming) { LinphoneCore *lc=linphone_chat_room_get_lc(cr); - LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1); + LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage); msg->chat_room=(LinphoneChatRoom*)cr; msg->message=message?ms_strdup(message):NULL; msg->external_body_url=external_body_url?ms_strdup(external_body_url):NULL; @@ -803,14 +815,40 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) /** * Destroys a LinphoneChatMessage. **/ -void linphone_chat_message_destroy(LinphoneChatMessage* msg) { +void linphone_chat_message_destroy(LinphoneChatMessage* msg){ + belle_sip_object_unref(msg); +} + + +/** + * Destroys a LinphoneChatMessage. +**/ +static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) { if (msg->op) sal_op_release(msg->op); if (msg->message) ms_free(msg->message); if (msg->external_body_url) ms_free(msg->external_body_url); if (msg->from) linphone_address_destroy(msg->from); if (msg->to) linphone_address_destroy(msg->to); if (msg->custom_headers) sal_custom_header_free(msg->custom_headers); - ms_free(msg); +} + + +/** + * Acquire a reference to the chat message. + * @param msg the chat message + * @return the same chat message +**/ +LinphoneChatMessage * linphone_chat_message_ref(LinphoneChatMessage *msg){ + belle_sip_object_ref(msg); + return msg; +} + +/** + * Release reference to the chat message. + * @param msg the chat message. +**/ +void linphone_chat_message_unref(LinphoneChatMessage *msg){ + belle_sip_object_unref(msg); } /** diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f4f34b8c6..7448341aa 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1067,6 +1067,8 @@ LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *ms LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state); LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message); LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message); +LINPHONE_PUBLIC LinphoneChatMessage * linphone_chat_message_ref(LinphoneChatMessage *msg); +LINPHONE_PUBLIC void linphone_chat_message_unref(LinphoneChatMessage *msg); LINPHONE_PUBLIC void linphone_chat_message_destroy(LinphoneChatMessage* msg); LINPHONE_PUBLIC void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from); LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message); diff --git a/coreapi/private.h b/coreapi/private.h index 9fa89dd3a..69ca8c728 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -132,6 +132,7 @@ typedef enum _LinphoneChatMessageDir{ } LinphoneChatMessageDir; struct _LinphoneChatMessage { + belle_sip_object_t base; LinphoneChatRoom* chat_room; LinphoneChatMessageDir dir; char* message; @@ -149,6 +150,8 @@ struct _LinphoneChatMessage { SalOp *op; }; +BELLE_SIP_DECLARE_VPTR(LinphoneChatMessage); + typedef struct StunCandidate{ char addr[64]; int port; @@ -862,7 +865,8 @@ BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000) BELLE_SIP_TYPE_ID(LinphoneContactSearch), BELLE_SIP_TYPE_ID(LinphoneContactProvider), BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider), -BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch) +BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch), +BELLE_SIP_TYPE_ID(LinphoneChatMessage) BELLE_SIP_DECLARE_TYPES_END From fd813601605e2f4e2cbd70e2cdb96806e3e78e41 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 11 Apr 2014 14:46:21 +0200 Subject: [PATCH 415/439] fix management of LinphoneChatMessage in android glue add authInfoRequested implementation. --- .../core/tutorials/TutorialBuddyStatus.java | 8 ++++- .../core/tutorials/TutorialChatRoom.java | 2 +- .../core/tutorials/TutorialHelloWorld.java | 2 +- .../core/tutorials/TutorialRegistration.java | 2 +- coreapi/linphonecore_jni.cc | 31 +++++++++-------- .../linphone/core/LinphoneChatMessage.java | 5 --- .../core/LinphoneChatMessageImpl.java | 33 +++++++------------ .../linphone/core/LinphoneChatRoomImpl.java | 8 ++--- 8 files changed, 44 insertions(+), 47 deletions(-) diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index c9ccb9105..6424442e7 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -97,7 +97,6 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } public void show(LinphoneCore lc) {} public void byeReceived(LinphoneCore lc, String from) {} - public void authInfoRequested(LinphoneCore lc, String realm, String username) {} public void displayStatus(LinphoneCore lc, String message) {} public void displayMessage(LinphoneCore lc, String message) {} public void displayWarning(LinphoneCore lc, String message) {} @@ -294,5 +293,12 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void authInfoRequested(LinphoneCore lc, String realm, + String username, String Domain) { + // 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 e2dc10d34..bf1d93d6d 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -73,7 +73,7 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa public void show(LinphoneCore lc) {} public void byeReceived(LinphoneCore lc, String from) {} - public void authInfoRequested(LinphoneCore lc, String realm, String username) {} + public void authInfoRequested(LinphoneCore lc, String realm, String username, String domain) {} public void displayStatus(LinphoneCore lc, String message) {} public void displayMessage(LinphoneCore lc, String message) {} public void displayWarning(LinphoneCore lc, String message) {} diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index e0faf9d92..8c1eeafb4 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -67,7 +67,7 @@ public class TutorialHelloWorld implements LinphoneCoreListener { public void show(LinphoneCore lc) {} public void byeReceived(LinphoneCore lc, String from) {} - public void authInfoRequested(LinphoneCore lc, String realm, String username) {} + public void authInfoRequested(LinphoneCore lc, String realm, String username, String domain) {} public void displayStatus(LinphoneCore lc, String message) {} public void displayMessage(LinphoneCore lc, String message) {} public void displayWarning(LinphoneCore lc, String message) {} diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index c3aebd307..91a778feb 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -78,7 +78,7 @@ public class TutorialRegistration implements LinphoneCoreListener { public void show(LinphoneCore lc) {} public void byeReceived(LinphoneCore lc, String from) {} - public void authInfoRequested(LinphoneCore lc, String realm, String username) {} + public void authInfoRequested(LinphoneCore lc, String realm, String username, String domain) {} public void displayStatus(LinphoneCore lc, String message) {} public void displayMessage(LinphoneCore lc, String message) {} public void displayWarning(LinphoneCore lc, String message) {} diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 2b0c79897..bb94573f5 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2447,13 +2447,6 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_destroy(JNIEnv* env linphone_chat_room_destroy((LinphoneChatRoom*)ptr); } -extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setUserData(JNIEnv* env - ,jobject thiz - ,jlong ptr) { - jobject ud = env->NewGlobalRef(thiz); - linphone_chat_message_set_user_data((LinphoneChatMessage*)ptr,(void*) ud); -} - extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_store(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -2554,6 +2547,12 @@ extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getStorageId(JNIE return (jint) linphone_chat_message_get_storage_id((LinphoneChatMessage*)ptr); } +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_unref(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_message_unref((LinphoneChatMessage*)ptr); +} + extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getChatRooms(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -2592,26 +2591,32 @@ static void chat_room_impl_callback(LinphoneChatMessage* msg, LinphoneChatMessag jobject listener = (jobject) ud; jclass clazz = (jclass) env->GetObjectClass(listener); jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageStateChanged","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneChatMessage$State;)V"); - + jobject jmessage=(jobject)linphone_chat_message_get_user_data(msg); LinphoneCore *lc = linphone_chat_room_get_lc(linphone_chat_message_get_chat_room(msg)); LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); env->CallVoidMethod( listener, method, - (jobject)linphone_chat_message_get_user_data(msg), + jmessage, env->CallStaticObjectMethod(lcData->chatMessageStateClass,lcData->chatMessageStateFromIntId,(jint)state)); - + if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) { env->DeleteGlobalRef(listener); + env->DeleteGlobalRef(jmessage); + linphone_chat_message_set_user_data(msg,NULL); } } extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* env ,jobject thiz - ,jlong ptr - ,jlong jmessage + ,jlong chatroom_ptr + ,jobject message + ,jlong messagePtr ,jobject jlistener) { jobject listener = env->NewGlobalRef(jlistener); - linphone_chat_room_send_message2((LinphoneChatRoom*)ptr, (LinphoneChatMessage*)jmessage, chat_room_impl_callback, (void*)listener); + message = env->NewGlobalRef(message); + linphone_chat_message_ref((LinphoneChatMessage*)messagePtr); + linphone_chat_message_set_user_data((LinphoneChatMessage*)messagePtr, message); + linphone_chat_room_send_message2((LinphoneChatRoom*)chatroom_ptr, (LinphoneChatMessage*)messagePtr, chat_room_impl_callback, (void*)listener); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index 356294102..d51a19251 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -52,11 +52,6 @@ public interface LinphoneChatMessage { } } - long getNativePtr(); - - Object getUserData(); - - void setUserData(); /** * get text associated to this LinphoneChatMessage diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index a891cad8b..c48c8a5cc 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -2,7 +2,6 @@ package org.linphone.core; public class LinphoneChatMessageImpl implements LinphoneChatMessage { protected final long nativePtr; - private native void setUserData(long ptr); private native String getText(long ptr); private native long getPeerAddress(long ptr); private native String getExternalBodyUrl(long ptr); @@ -14,27 +13,16 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native boolean isOutgoing(long ptr); private native void store(long ptr); private native int getStorageId(long ptr); + private native void unref(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; - setUserData(); } public long getNativePtr() { return nativePtr; } - @Override - public Object getUserData() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void setUserData() { - setUserData(nativePtr); - } - @Override public String getText() { return getText(nativePtr); @@ -97,12 +85,15 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native int getReason(long ptr); - public Reason getReason() { - return Reason.fromInt(getReason(nativePtr)); - } - private native long getErrorInfo(long nativePtr); - @Override - public ErrorInfo getErrorInfo() { - return new ErrorInfoImpl(getErrorInfo(nativePtr)); - } + public Reason getReason() { + return Reason.fromInt(getReason(nativePtr)); + } + private native long getErrorInfo(long nativePtr); + @Override + public ErrorInfo getErrorInfo() { + return new ErrorInfoImpl(getErrorInfo(nativePtr)); + } + protected void finalize(){ + unref(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index c2021e379..7901272c9 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -26,7 +26,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native long createLinphoneChatMessage(long ptr, String message); private native long getPeerAddress(long ptr); private native void sendMessage(long ptr, String message); - private native void sendMessage2(long ptr, long message, StateListener listener); + private native void sendMessage2(long ptr, Object msg, long messagePtr, StateListener listener); private native long[] getHistory(long ptr, int limit); private native void destroy(long ptr); private native int getUnreadMessagesCount(long ptr); @@ -54,7 +54,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { @Override public void sendMessage(LinphoneChatMessage message, StateListener listener) { - sendMessage2(nativePtr, message.getNativePtr(), listener); + sendMessage2(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr(), listener); } @Override @@ -104,12 +104,12 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public void deleteMessage(LinphoneChatMessage message) { if (message != null) - deleteMessage(nativePtr, message.getNativePtr()); + deleteMessage(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr()); } public void updateUrl(LinphoneChatMessage message) { if (message != null) - updateUrl(nativePtr, message.getNativePtr()); + updateUrl(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr()); } @Override From 08645f8eeaa60f1b8c6bd30d9871389ad18196bf Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 11 Apr 2014 16:20:05 +0200 Subject: [PATCH 416/439] Add lp_config_new_from_buffer --- coreapi/lpconfig.c | 206 +++++++++++++++++++++++------------------- coreapi/lpconfig.h | 40 +++++--- tester/setup_tester.c | 45 ++++++--- 3 files changed, 171 insertions(+), 120 deletions(-) diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 8df196df2..6e51d257c 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -177,101 +177,107 @@ LpItem *lp_section_find_item(const LpSection *sec, const char *name){ return NULL; } -void lp_config_parse(LpConfig *lpconfig, FILE *file){ - char tmp[MAX_LEN]= {'\0'}; - LpSection *cur=NULL; +static LpSection* lp_config_parse_line(LpConfig* lpconfig, const char* line, LpSection* cur) { LpSectionParam *params = NULL; char *pos1,*pos2; int nbs; - char secname[MAX_LEN]; - char key[MAX_LEN]; - char value[MAX_LEN]; + static char secname[MAX_LEN]; + static char key[MAX_LEN]; + static char value[MAX_LEN]; LpItem *item; + pos1=strchr(line,'['); + if (pos1!=NULL && is_first_char(line,pos1) ){ + pos2=strchr(pos1,']'); + if (pos2!=NULL){ + secname[0]='\0'; + /* found section */ + *pos2='\0'; + nbs = sscanf(pos1+1, "%s", secname); + if (nbs >= 1) { + if (strlen(secname) > 0) { + cur = lp_config_find_section (lpconfig,secname); + if (cur == NULL) { + cur = lp_section_new(secname); + lp_config_add_section(lpconfig, cur); + } + + if (pos2 > pos1 + 1 + strlen(secname)) { + /* found at least one section param */ + pos2 = pos1 + 1 + strlen(secname) + 1; // Remove the white space after the secname + pos1 = strchr(pos2, '='); + while (pos1 != NULL) { + /* for each section param */ + key[0] = '\0'; + value[0] = '\0'; + *pos1 = ' '; + if (sscanf(pos2, "%s %s", key, value) == 2) { + params = lp_section_param_new(key, value); + lp_config_add_section_param(cur, params); + + pos2 += strlen(key) + strlen(value) + 2; // Remove the = sign + the white space after each param + pos1 = strchr(pos2, '='); + } else { + ms_warning("parse section params error !"); + pos1 = NULL; + } + } + } + } + } else { + ms_warning("parse error!"); + } + } + }else { + pos1=strchr(line,'='); + if (pos1!=NULL){ + key[0]='\0'; + + *pos1='\0'; + if (sscanf(line,"%s",key)>0){ + + pos1++; + pos2=strchr(pos1,'\r'); + if (pos2==NULL) + pos2=strchr(pos1,'\n'); + if (pos2==NULL) pos2=pos1+strlen(pos1); + else { + *pos2='\0'; /*replace the '\n' */ + } + /* remove ending white spaces */ + for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0'; + + if (pos2-pos1>=0){ + /* found a pair key,value */ + + if (cur!=NULL){ + item=lp_section_find_item(cur,key); + if (item==NULL){ + lp_section_add_item(cur,lp_item_new(key,pos1)); + }else{ + ortp_free(item->value); + item->value=ortp_strdup(pos1); + } + /*ms_message("Found %s=%s",key,pos1);*/ + }else{ + ms_warning("found key,item but no sections"); + } + } + } + } + } + return cur; +} + +void lp_config_parse(LpConfig *lpconfig, FILE *file){ + char tmp[MAX_LEN]= {'\0'}; + LpSection* current_section = NULL; + if (file==NULL) return; while(fgets(tmp,MAX_LEN,file)!=NULL){ tmp[sizeof(tmp) -1] = '\0'; - pos1=strchr(tmp,'['); - if (pos1!=NULL && is_first_char(tmp,pos1) ){ - pos2=strchr(pos1,']'); - if (pos2!=NULL){ - secname[0]='\0'; - /* found section */ - *pos2='\0'; - nbs = sscanf(pos1+1, "%s", secname); - if (nbs >= 1) { - if (strlen(secname) > 0) { - cur = lp_config_find_section (lpconfig,secname); - if (cur == NULL) { - cur = lp_section_new(secname); - lp_config_add_section(lpconfig, cur); - } - - if (pos2 > pos1 + 1 + strlen(secname)) { - /* found at least one section param */ - pos2 = pos1 + 1 + strlen(secname) + 1; // Remove the white space after the secname - pos1 = strchr(pos2, '='); - while (pos1 != NULL) { - /* for each section param */ - key[0] = '\0'; - value[0] = '\0'; - *pos1 = ' '; - if (sscanf(pos2, "%s %s", key, value) == 2) { - params = lp_section_param_new(key, value); - lp_config_add_section_param(cur, params); - - pos2 += strlen(key) + strlen(value) + 2; // Remove the = sign + the white space after each param - pos1 = strchr(pos2, '='); - } else { - ms_warning("parse section params error !"); - pos1 = NULL; - } - } - } - } - } else { - ms_warning("parse error!"); - } - } - }else { - pos1=strchr(tmp,'='); - if (pos1!=NULL){ - key[0]='\0'; - - *pos1='\0'; - if (sscanf(tmp,"%s",key)>0){ - - pos1++; - pos2=strchr(pos1,'\r'); - if (pos2==NULL) - pos2=strchr(pos1,'\n'); - if (pos2==NULL) pos2=pos1+strlen(pos1); - else { - *pos2='\0'; /*replace the '\n' */ - } - /* remove ending white spaces */ - for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0'; - - if (pos2-pos1>=0){ - /* found a pair key,value */ - - if (cur!=NULL){ - item=lp_section_find_item(cur,key); - if (item==NULL){ - lp_section_add_item(cur,lp_item_new(key,pos1)); - }else{ - ortp_free(item->value); - item->value=ortp_strdup(pos1); - } - /*ms_message("Found %s=%s",key,pos1);*/ - }else{ - ms_warning("found key,item but no sections"); - } - } - } - } - } + current_section = lp_config_parse_line(lpconfig, tmp, current_section); } } @@ -279,9 +285,27 @@ LpConfig * lp_config_new(const char *filename){ return lp_config_new_with_factory(filename, NULL); } +LpConfig * lp_config_new_from_buffer(const char *buffer){ + LpConfig* conf = lp_new0(LpConfig,1); + LpSection* current_section = NULL; + + char* ptr = ms_strdup(buffer); + char* strtok_storage = NULL; + char* line = strtok_r(ptr, "\n", &strtok_storage); + + while( line != NULL ){ + current_section = lp_config_parse_line(conf,line,current_section); + line = strtok_r(NULL, "\n", &strtok_storage); + } + + ms_free(ptr); + + return conf; +} + LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) { LpConfig *lpconfig=lp_new0(LpConfig,1); - + if (config_filename!=NULL){ ms_message("Using (r/w) config information from %s", config_filename); lpconfig->filename=ortp_strdup(config_filename); @@ -547,7 +571,7 @@ int lp_config_get_default_int(const LpConfig *lpconfig, const char *section, con char default_section[MAX_LEN]; strcpy(default_section, section); strcat(default_section, DEFAULT_VALUES_SUFFIX); - + return lp_config_get_int(lpconfig, default_section, key, default_value); } @@ -555,7 +579,7 @@ int64_t lp_config_get_default_int64(const LpConfig *lpconfig, const char *sectio char default_section[MAX_LEN]; strcpy(default_section, section); strcat(default_section, DEFAULT_VALUES_SUFFIX); - + return lp_config_get_int64(lpconfig, default_section, key, default_value); } @@ -563,7 +587,7 @@ float lp_config_get_default_float(const LpConfig *lpconfig, const char *section, char default_section[MAX_LEN]; strcpy(default_section, section); strcat(default_section, DEFAULT_VALUES_SUFFIX); - + return lp_config_get_float(lpconfig, default_section, key, default_value); } @@ -571,6 +595,6 @@ const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *s char default_section[MAX_LEN]; strcpy(default_section, section); strcat(default_section, DEFAULT_VALUES_SUFFIX); - + return lp_config_get_string(lpconfig, default_section, key, default_value); } diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 0e735c1a7..f0f330c18 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #ifndef LPCONFIG_H #define LPCONFIG_H #include @@ -33,7 +33,7 @@ /** * The LpConfig object is used to manipulate a configuration file. - * + * * @ingroup misc * The format of the configuration file is a .ini like format: * - sections are defined in [] @@ -64,6 +64,16 @@ extern "C" { */ LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename); +/** + * Instantiates a LpConfig object from a user provided buffer. + * + * @ingroup misc + * @param buffer the buffer from which the lpconfig will be retrieved. We expect the buffer to be null-terminated. + * @see lp_config_new_with_factory + * @see lp_config_new + */ +LINPHONE_PUBLIC LpConfig * lp_config_new_from_buffer(const char *buffer); + /** * Instantiates a LpConfig object from a user config file and a factory config file. * @@ -88,7 +98,7 @@ LINPHONE_PUBLIC int lp_config_read_file(LpConfig *lpconfig, const char *filename /** * Retrieves a configuration item as a string, given its section, key, and default value. - * + * * @ingroup misc * The default value string is returned if the config item isn't found. **/ @@ -105,7 +115,7 @@ LINPHONE_PUBLIC bool_t lp_config_get_range(const LpConfig *lpconfig, const char /** * Retrieves a configuration item as an integer, given its section, key, and default value. - * + * * @ingroup misc * The default integer value is returned if the config item isn't found. **/ @@ -113,7 +123,7 @@ LINPHONE_PUBLIC int lp_config_get_int(const LpConfig *lpconfig,const char *secti /** * Retrieves a configuration item as a 64 bit integer, given its section, key, and default value. - * + * * @ingroup misc * The default integer value is returned if the config item isn't found. **/ @@ -121,14 +131,14 @@ LINPHONE_PUBLIC int64_t lp_config_get_int64(const LpConfig *lpconfig,const char /** * Retrieves a configuration item as a float, given its section, key, and default value. - * + * * @ingroup misc * The default float value is returned if the config item isn't found. **/ LINPHONE_PUBLIC float lp_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value); /** - * Sets a string config item + * Sets a string config item * * @ingroup misc **/ @@ -167,11 +177,11 @@ LINPHONE_PUBLIC void lp_config_set_int64(LpConfig *lpconfig,const char *section, * * @ingroup misc **/ -LINPHONE_PUBLIC void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value); +LINPHONE_PUBLIC void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value); /** * Writes the config file to disk. - * + * * @ingroup misc **/ LINPHONE_PUBLIC int lp_config_sync(LpConfig *lpconfig); @@ -211,7 +221,7 @@ LINPHONE_PUBLIC void lp_config_destroy(LpConfig *cfg); /** * Retrieves a default configuration item as an integer, given its section, key, and default value. - * + * * @ingroup misc * The default integer value is returned if the config item isn't found. **/ @@ -219,7 +229,7 @@ LINPHONE_PUBLIC int lp_config_get_default_int(const LpConfig *lpconfig, const ch /** * Retrieves a default configuration item as a 64 bit integer, given its section, key, and default value. - * + * * @ingroup misc * The default integer value is returned if the config item isn't found. **/ @@ -227,7 +237,7 @@ LINPHONE_PUBLIC int64_t lp_config_get_default_int64(const LpConfig *lpconfig, co /** * Retrieves a default configuration item as a float, given its section, key, and default value. - * + * * @ingroup misc * The default float value is returned if the config item isn't found. **/ @@ -235,7 +245,7 @@ LINPHONE_PUBLIC float lp_config_get_default_float(const LpConfig *lpconfig, cons /** * Retrieves a default configuration item as a string, given its section, key, and default value. - * + * * @ingroup misc * The default value string is returned if the config item isn't found. **/ @@ -243,12 +253,12 @@ LINPHONE_PUBLIC const char* lp_config_get_default_string(const LpConfig *lpconfi /** * Retrieves a section parameter item as a string, given its section and key. - * + * * @ingroup misc * The default value string is returned if the config item isn't found. **/ LINPHONE_PUBLIC const char* lp_config_get_section_param_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value); - + #ifdef __cplusplus } #endif diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 0e4299dbc..dc30e058e 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -1,19 +1,19 @@ /* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 Belledonne Communications SARL - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. + This program is free software: you can 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. + This program is distributed in the hope that 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include @@ -72,7 +72,7 @@ static void linphone_interpret_url_test() LinphoneCore* lc; const char* sips_address = "sips:margaux@sip.linphone.org"; LinphoneAddress* address; - + memset ( &v_table,0,sizeof ( v_table ) ); lc = linphone_core_new ( &v_table,NULL,NULL,NULL ); CU_ASSERT_PTR_NOT_NULL_FATAL ( lc ); @@ -89,12 +89,29 @@ static void linphone_interpret_url_test() linphone_core_destroy ( lc ); } +static void linphone_lpconfig_from_buffer(){ + + static const char* buffer = "[buffer]\ntest=ok"; + static const char* buffer_linebreaks = "[buffer_linebreaks]\n\n\n\r\n\n\r\ntest=ok"; + LpConfig* conf; + + conf = lp_config_new_from_buffer(buffer); + CU_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"buffer","test",""),"ok"); + lp_config_destroy(conf); + + conf = lp_config_new_from_buffer(buffer_linebreaks); + CU_ASSERT_STRING_EQUAL(lp_config_get_string(conf,"buffer_linebreaks","test",""),"ok"); + lp_config_destroy(conf); + +} + test_t setup_tests[] = { { "Linphone Address", linphone_address_test }, { "Linphone core init/uninit", core_init_test }, { "Linphone random transport port",core_sip_transport_test}, - { "Linphone interpret url", linphone_interpret_url_test } + { "Linphone interpret url", linphone_interpret_url_test }, + { "LPConfig from buffer", linphone_lpconfig_from_buffer } }; test_suite_t setup_test_suite = { From 7427b281693eeaa2483725e225967cf6cf4772e8 Mon Sep 17 00:00:00 2001 From: Guillaume Beraudo Date: Mon, 14 Apr 2014 10:19:43 +0200 Subject: [PATCH 417/439] Fix real early media command line. --- console/linphonec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index f08c0f94d..ca7d6cafa 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -914,7 +914,7 @@ print_usage (int exit_status) " -l logfile specify the log file for your SIP phone\n" " -s sipaddress specify the sip call to do at startup\n" " -a enable auto answering for incoming calls\n" -" --real-early-media enable sending early media using real audio/video (beware of privacy issue)\n" +" --real-early-media enable sending early media using real audio/video (beware of privacy issue)\n" " -V enable video features globally (disabled by default)\n" " -C enable video capture only (disabled by default)\n" " -D enable video display only (disabled by default)\n" @@ -1238,7 +1238,7 @@ linphonec_parse_cmdline(int argc, char **argv) { auto_answer = TRUE; } - else if (strncmp ("--real-early-media", argv[arg_num], 2) == 0) + else if (strncmp ("--real-early-media", argv[arg_num], strlen("--real-early-media")) == 0) { real_early_media_sending = TRUE; } From 162f121348d175e217d18141bbb2839f73b8dbb3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 11 Apr 2014 17:16:29 +0200 Subject: [PATCH 418/439] better mgt of refresher in case of registration error --- coreapi/proxy.c | 6 ++++++ tester/register_tester.c | 28 ++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 74c8a7730..a526f337b 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -270,6 +270,9 @@ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ if (obj->state == LinphoneRegistrationOk || obj->state == LinphoneRegistrationProgress) { sal_unregister(obj->op); + } else { + /*stop refresher*/ + if (obj->op) sal_op_stop_refreshing(obj->op); } } } @@ -351,6 +354,9 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed"); } ms_free(proxy_string); + } else { + /*stop refresher, just in case*/ + if (obj->op) sal_op_stop_refreshing(obj->op); } } diff --git a/tester/register_tester.c b/tester/register_tester.c index 28850e141..a0d63e278 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -332,8 +332,7 @@ static void authenticated_register_with_wrong_late_credentials(){ linphone_core_manager_destroy(mgr); } -static void authenticated_register_with_wrong_credentials_with_params(const char* user_agent) { - LinphoneCoreManager *mgr; +static void authenticated_register_with_wrong_credentials_with_params_base(const char* user_agent,LinphoneCoreManager *mgr) { stats* counters; LCSipTransports transport = {5070,5070,0,5071}; LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,"wrong passwd",NULL,auth_domain,NULL); /*create authentication structure from identity*/ @@ -341,8 +340,6 @@ static void authenticated_register_with_wrong_credentials_with_params(const char sprintf(route,"sip:%s",test_route); - mgr=linphone_core_manager_new(NULL); - mgr->lc->vtable.auth_info_requested=auth_info_requested2; sal_set_refresher_retry_after(mgr->lc->sal,500); @@ -372,11 +369,33 @@ static void authenticated_register_with_wrong_credentials_with_params(const char } } + } +static void authenticated_register_with_wrong_credentials_with_params(const char* user_agent) { + LinphoneCoreManager *mgr = linphone_core_manager_new(NULL); + authenticated_register_with_wrong_credentials_with_params_base(user_agent,mgr); linphone_core_manager_destroy(mgr); } static void authenticated_register_with_wrong_credentials() { authenticated_register_with_wrong_credentials_with_params(NULL); } +static void authenticated_register_with_wrong_credentials_2() { + LinphoneCoreManager *mgr = linphone_core_manager_new(NULL); + stats* counters = get_stats(mgr->lc); + int current_in_progress; + LinphoneProxyConfig* proxy; + + authenticated_register_with_wrong_credentials_with_params_base(NULL,mgr); + + linphone_core_get_default_proxy(mgr->lc,&proxy); + /*Make sure registration attempts are stopped*/ + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_register(proxy,FALSE); + linphone_proxy_config_done(proxy); + current_in_progress=counters->number_of_LinphoneRegistrationProgress; + CU_ASSERT_FALSE(wait_for(mgr->lc,mgr->lc,&counters->number_of_LinphoneRegistrationProgress,current_in_progress+1)); + + linphone_core_manager_destroy(mgr); +} static void authenticated_register_with_wrong_credentials_without_403() { authenticated_register_with_wrong_credentials_with_params("tester-no-403"); } @@ -655,6 +674,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 }, + { "Digest auth with wrong credentials, check if registration attempts are stopped", authenticated_register_with_wrong_credentials_2 }, { "Digest auth with wrong credentials without 403", authenticated_register_with_wrong_credentials_without_403}, { "Authenticated register with wrong late credentials", authenticated_register_with_wrong_late_credentials}, { "Authenticated register with late credentials", authenticated_register_with_late_credentials }, From 2ae4719376dad8ae54106cfd2ab6357d1b110993 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 14 Apr 2014 10:38:03 +0200 Subject: [PATCH 419/439] change some registration test to wait until registration cleared to arive --- mediastreamer2 | 2 +- tester/register_tester.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index b76e3dde1..34ced9269 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b76e3dde111af0d24be4ac5f1d4f633361e654c1 +Subproject commit 34ced9269b1e8f8272b25f627db37dc12ce05317 diff --git a/tester/register_tester.c b/tester/register_tester.c index a0d63e278..0798bd61f 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -567,11 +567,17 @@ static void io_recv_error_without_active_register(){ 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); + } + ms_list_free(proxys); + /*wait for unregistrations*/ + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationCleared,register_ok /*because 1 udp*/)); + + 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_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); From 28f4a815f6be83516748a2af610d69629f0ab593 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Apr 2014 15:25:28 +0200 Subject: [PATCH 420/439] prevent concurrent registers using linphone_core_refresh_registers() being called multiple times. --- coreapi/proxy.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a526f337b..466c77b93 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -365,7 +365,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ * This is useful if for example you resuming from suspend, thus IP address may have changed. **/ void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj){ - if (obj->reg_sendregister && obj->op){ + if (obj->reg_sendregister && obj->op && obj->state!=LinphoneRegistrationProgress){ if (sal_register_refresh(obj->op,obj->expires) == 0) { linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress, "Refresh registration"); } @@ -1326,15 +1326,16 @@ 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; bool_t update_friends=FALSE; - if (linphone_core_should_subscribe_friends_only_when_registered(lc)){ - update_friends=(state==LinphoneRegistrationOk && cfg->state!=LinphoneRegistrationOk) - || (state!=LinphoneRegistrationOk && cfg->state==LinphoneRegistrationOk); - } - ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg, + + if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/ + ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg, linphone_proxy_config_get_identity(cfg), linphone_registration_state_to_string(cfg->state), linphone_registration_state_to_string(state)); - if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/ + if (linphone_core_should_subscribe_friends_only_when_registered(lc)){ + update_friends=(state==LinphoneRegistrationOk && cfg->state!=LinphoneRegistrationOk) + || (state!=LinphoneRegistrationOk && cfg->state==LinphoneRegistrationOk); + } cfg->state=state; if (update_friends){ From 80c1f93b9575c9871ea9f7e78a90680dfc22f536 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Apr 2014 16:10:56 +0200 Subject: [PATCH 421/439] fix crash with RTCP xr --- coreapi/linphonecall.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index cf69902c7..e3127a3e6 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2222,6 +2222,11 @@ void linphone_call_stop_video_stream(LinphoneCall *call) { #endif } +static void unset_rtp_profile(LinphoneCall *call, int i){ + if (call->sessions[i].rtp_session) + rtp_session_set_profile(call->sessions[i].rtp_session,&av_profile); +} + void linphone_call_stop_media_streams(LinphoneCall *call){ if (call->audiostream || call->videostream) { linphone_call_stop_audio_stream(call); @@ -2235,10 +2240,12 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ if (call->audio_profile){ rtp_profile_destroy(call->audio_profile); call->audio_profile=NULL; + unset_rtp_profile(call,0); } if (call->video_profile){ rtp_profile_destroy(call->video_profile); call->video_profile=NULL; + unset_rtp_profile(call,1); } } From a32c864292e147b769bc6f2b19735593cf84f41e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 14 Apr 2014 16:28:57 +0200 Subject: [PATCH 422/439] fix invalid read in gtk app call log management --- gtk/calllogs.c | 8 +++++--- tester/call_tester.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 2f7e8f769..7a4840aa8 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -293,7 +293,10 @@ void linphone_gtk_call_log_update(GtkWidget *w){ #endif lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),addr); if(lf != NULL){ - display=linphone_address_get_display_name(linphone_friend_get_address(lf)); + if ((display=linphone_address_get_display_name(linphone_friend_get_address(lf)))) { + /*update display name from friend*/ + linphone_address_set_display_name(la,display); + } } else { display=linphone_address_get_display_name(la); } @@ -302,9 +305,8 @@ void linphone_gtk_call_log_update(GtkWidget *w){ if (display==NULL){ display=linphone_address_get_domain (la); } - } else { - linphone_address_set_display_name(la,display); } + if (linphone_call_log_get_quality(cl)!=-1){ snprintf(quality,sizeof(quality),"%.1f",linphone_call_log_get_quality(cl)); }else snprintf(quality,sizeof(quality)-1,"%s",_("n/a")); diff --git a/tester/call_tester.c b/tester/call_tester.c index 2a18b30d2..c655e4b88 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -355,7 +355,7 @@ static void call_with_dns_time_out(void) { 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_invite(marie->lc,"\"t\x8et\x8e\" sip:toto@toto.com"); /*just to use non ascii values*/ for(i=0;i<10;i++){ ms_usleep(200000); linphone_core_iterate(marie->lc); From e5d8ff817a5de726d75a6a69791d6a9603fe6460 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 14 Apr 2014 19:13:13 +0200 Subject: [PATCH 423/439] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 34ced9269..13d0cee33 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 34ced9269b1e8f8272b25f627db37dc12ce05317 +Subproject commit 13d0cee33672690daca1a7252c9f3a7022da95bd From 15d7543a49844b9b0bf392f70716cb678e3d281c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 15 Apr 2014 13:43:25 +0200 Subject: [PATCH 424/439] change default behavior regarding changing srtp keys. They are now not changed by reINVITEs. --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e3127a3e6..4b5f985d4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -248,7 +248,7 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ LinphoneCore *lc=call->core; int i; SalMediaDescription *old_md=call->localdesc; - bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); + bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1); for(i=0; in_active_streams; i++) { if (md->streams[i].proto == SalProtoRtpSavp) { From 8c1be075000abb15f38cc0318c5ba50568e17196 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 15 Apr 2014 15:18:01 +0200 Subject: [PATCH 425/439] update ms2 and ortp --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 13d0cee33..1cdbfc4d6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 13d0cee33672690daca1a7252c9f3a7022da95bd +Subproject commit 1cdbfc4d675784aa1832ad9af10c5d8aa6c11776 diff --git a/oRTP b/oRTP index 6330e3d1c..beee1f20d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 6330e3d1c792515826be7116fb31086284faa430 +Subproject commit beee1f20d69af3d04cd27fcc00b3830620066367 From 0bb0bb23eaea96f4e634544afeb87d9571111ad7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 15 Apr 2014 15:37:02 +0200 Subject: [PATCH 426/439] fix non-null terminated string in provisioning from file --- coreapi/remote_provisioning.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/remote_provisioning.c b/coreapi/remote_provisioning.c index bcae9e798..7b5d6367d 100644 --- a/coreapi/remote_provisioning.c +++ b/coreapi/remote_provisioning.c @@ -62,6 +62,7 @@ static int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* fseek(f, 0, SEEK_SET); char* provisioning = ms_malloc(fsize + 1); + provisioning[fsize]='\0'; if (fread(provisioning, fsize, 1, f)==0){ ms_error("Could not read xml provisioning file from %s",file_path); status=-1; From f8cd001a225b5544515afac0753bf997b51a0590 Mon Sep 17 00:00:00 2001 From: Margaux Clerc Date: Wed, 16 Apr 2014 13:00:20 +0200 Subject: [PATCH 427/439] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 1cdbfc4d6..41db9323b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1cdbfc4d675784aa1832ad9af10c5d8aa6c11776 +Subproject commit 41db9323be6a6d136949ee5fdba1198c38a7d787 From 92762859a476f2f82396d94d0e5cfa003ba37bf8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 16 Apr 2014 15:35:10 +0200 Subject: [PATCH 428/439] stop warning about missing tls --- coreapi/linphonecore.c | 8 +++++--- tester/call_tester.c | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d6b3f842c..b80514e58 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1955,9 +1955,11 @@ static int apply_transports(LinphoneCore *lc){ transport_error(lc,"tcp",tr->tcp_port); } } - if (tr->tls_port!=0){ - if (sal_listen_port (sal,anyaddr,tr->tls_port,SalTransportTLS,TRUE)!=0){ - transport_error(lc,"tls",tr->tls_port); + if (linphone_core_sip_transport_supported(LinphoneTransportTls)){ + if (tr->tls_port!=0){ + if (sal_listen_port (sal,anyaddr,tr->tls_port,SalTransportTLS,TRUE)!=0){ + transport_error(lc,"tls",tr->tls_port); + } } } apply_user_agent(lc); diff --git a/tester/call_tester.c b/tester/call_tester.c index c655e4b88..3e8ef9475 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -542,6 +542,8 @@ static void _call_with_ice(bool_t random_ports) { 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)); + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + liblinphone_tester_check_rtcp(marie,pauline); /*then close the call*/ linphone_core_terminate_all_calls(pauline->lc); From 59655c7d51933cc3ed40056452efb7a7b285890e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 16 Apr 2014 16:21:08 +0200 Subject: [PATCH 429/439] fix compilation --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b80514e58..7c30c3b17 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1955,7 +1955,7 @@ static int apply_transports(LinphoneCore *lc){ transport_error(lc,"tcp",tr->tcp_port); } } - if (linphone_core_sip_transport_supported(LinphoneTransportTls)){ + if (linphone_core_sip_transport_supported(lc,LinphoneTransportTls)){ if (tr->tls_port!=0){ if (sal_listen_port (sal,anyaddr,tr->tls_port,SalTransportTLS,TRUE)!=0){ transport_error(lc,"tls",tr->tls_port); From f9c8c72c01978b6faa042dcaea942c688e60ee83 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 17 Apr 2014 16:02:25 +0200 Subject: [PATCH 430/439] refactor ICE in liblinphone so that processing is centralized in a few methods, rather than spread into several methods. --- coreapi/linphonecall.c | 107 ++++++++++++++++++++++++----------------- coreapi/linphonecore.c | 73 ++++++---------------------- coreapi/private.h | 1 + 3 files changed, 80 insertions(+), 101 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4b5f985d4..eb4a00551 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -648,14 +648,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_media_streams(call); switch (linphone_core_get_firewall_policy(call->core)) { case LinphonePolicyUseIce: - /*start ICE gathering*/ - linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op)); - linphone_call_start_media_streams_for_ice_gathering(call); - if (linphone_core_gather_ice_candidates(call->core,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - linphone_call_stop_media_streams_for_ice_gathering(call); - } + linphone_call_prepare_ice(call,TRUE); break; case LinphonePolicyUseStun: call->ping_time=linphone_core_run_stun_tests(call->core,call); @@ -1431,6 +1424,60 @@ static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, call->media_ports[stream_index].rtcp_port=rtp_session_get_local_rtcp_port(session); } +static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream_index, bool_t create_checklist){ + MediaStream *ms=stream_index == 0 ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream; + if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ + IceCheckList *cl; + rtp_session_set_pktinfo(ms->sessions.rtp_session, TRUE); + rtp_session_set_symmetric_rtp(ms->sessions.rtp_session, FALSE); + cl=ice_session_check_list(call->ice_session, stream_index); + if (cl == NULL && create_checklist) { + cl=ice_check_list_new(); + ice_session_add_check_list(call->ice_session, cl); + ms_message("Created new ICE check list for stream [%i]",stream_index); + } + if (cl){ + ms->ice_check_list = cl; + ice_check_list_set_rtp_session(ms->ice_check_list, ms->sessions.rtp_session); + } + } +} + +int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ + SalMediaDescription *remote; + bool_t has_video=FALSE; + + if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ + if (incoming_offer){ + remote=sal_call_get_remote_media_description(call->op); + has_video=linphone_core_media_description_contains_video_stream(remote); + }else has_video=call->params.has_video; + + _linphone_call_prepare_ice_for_stream(call,0,TRUE); + if (has_video) _linphone_call_prepare_ice_for_stream(call,1,TRUE); + /*start ICE gathering*/ + if (incoming_offer) + linphone_core_update_ice_from_remote_media_description(call,remote); + if (!ice_session_candidates_gathered(call->ice_session)){ + if (call->audiostream->ms.state==MSStreamInitialized) + audio_stream_prepare_sound(call->audiostream, NULL, NULL); +#ifdef VIDEO_ENABLED + if (has_video && call->videostream && call->videostream->ms.state==MSStreamInitialized) { + video_stream_prepare_video(call->videostream); + } +#endif + if (linphone_core_gather_ice_candidates(call->core,call)<0) { + /* Ice candidates gathering failed, proceed with the call anyway. */ + linphone_call_delete_ice_session(call); + linphone_call_stop_media_streams_for_ice_gathering(call); + return -1; + } + return 1;/*gathering in progress, wait*/ + } + } + return 0; +} + void linphone_call_init_audio_stream(LinphoneCall *call){ LinphoneCore *lc=call->core; AudioStream *audiostream; @@ -1481,18 +1528,11 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port); rtp_session_set_transports(audiostream->ms.sessions.rtp_session,artp,artcp); } - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ - rtp_session_set_pktinfo(audiostream->ms.sessions.rtp_session, TRUE); - rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session, FALSE); - if (ice_session_check_list(call->ice_session, 0) == NULL) { - ice_session_add_check_list(call->ice_session, ice_check_list_new()); - } - audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0); - ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.sessions.rtp_session); - } call->audiostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); + + _linphone_call_prepare_ice_for_stream(call,0,FALSE); } void linphone_call_init_video_stream(LinphoneCall *call){ @@ -1527,23 +1567,11 @@ void linphone_call_init_video_stream(LinphoneCall *call){ } call->videostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); + _linphone_call_prepare_ice_for_stream(call,1,FALSE); #ifdef TEST_EXT_RENDERER video_stream_set_render_callback(call->videostream,rendercb,NULL); #endif } - /*eventually re-create the ICE check list that may have been destroyed if the stream wasn't used recently*/ - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ - rtp_session_set_pktinfo(call->videostream->ms.sessions.rtp_session, TRUE); - rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session, FALSE); - if (ice_session_check_list(call->ice_session, 1) == NULL) { - ice_session_add_check_list(call->ice_session, ice_check_list_new()); - } - 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.sessions.rtp_session); - ms_message ("creating new ice video check list [%p] for session [%p]",call->videostream->ms.ice_check_list,call->videostream->ms.sessions.rtp_session); - } - - #else call->videostream=NULL; #endif @@ -2082,19 +2110,10 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut linphone_address_destroy(me); } -void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){ - audio_stream_prepare_sound(call->audiostream, NULL, NULL); -#ifdef VIDEO_ENABLED - if (call->videostream) { - video_stream_prepare_video(call->videostream); - } -#endif -} - void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ - audio_stream_unprepare_sound(call->audiostream); + if(call->audiostream && call->audiostream->ms.state==MSStreamPreparing) audio_stream_unprepare_sound(call->audiostream); #ifdef VIDEO_ENABLED - if (call->videostream) { + if (call->videostream && call->videostream->ms.state==MSStreamPreparing) { video_stream_unprepare_video(call->videostream); } #endif @@ -2671,8 +2690,10 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ break; } } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) { - linphone_core_start_accept_call_update(call->core, call); - linphone_core_update_ice_state_in_call_stats(call); + if (call->state==LinphoneCallUpdatedByRemote){ + linphone_core_start_accept_call_update(call->core, call); + linphone_core_update_ice_state_in_call_stats(call); + } } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) { ice_session_restart(call->ice_session); ice_session_set_role(call->ice_session, IR_Controlling); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7c30c3b17..bd852968e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2843,22 +2843,16 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const /* this call becomes now the current one*/ lc->current_call=call; linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); + call->log->start_date_time=time(NULL); linphone_call_init_media_streams(call); + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { /* Defer the start of the call after the ICE gathering process. */ - linphone_call_start_media_streams_for_ice_gathering(call); - call->log->start_date_time=time(NULL); - if (linphone_core_gather_ice_candidates(lc,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - linphone_call_stop_media_streams_for_ice_gathering(call); - } else { - defer = TRUE; - } + if (linphone_call_prepare_ice(call,FALSE)==1) + defer=TRUE; } else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) { #ifdef BUILD_UPNP - call->log->start_date_time=time(NULL); if (linphone_core_update_upnp(lc,call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ linphone_call_delete_upnp_session(call); @@ -2880,7 +2874,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const call->ping_op=sal_op_new(lc->sal); sal_ping(call->ping_op,from,real_url); sal_op_set_user_pointer(call->ping_op,call); - call->log->start_date_time=time(NULL); defer = TRUE; } } @@ -3106,9 +3099,7 @@ int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call){ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ const char *subject; - if (call->ice_session != NULL) { - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); - } + linphone_call_make_local_media_description(lc,call); #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); @@ -3155,10 +3146,6 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho // Video removing if((call->videostream != NULL) && !params->has_video) { - if (call->ice_session != NULL) { - ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list); - call->videostream->ms.ice_check_list = NULL; - } #ifdef BUILD_UPNP if(call->upnp_session != NULL) { if (linphone_core_update_upnp(lc, call)<0) { @@ -3171,27 +3158,18 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho #endif /* VIDEO_ENABLED */ _linphone_call_params_copy(&call->params,params); - linphone_call_make_local_media_description(lc, call); + err=linphone_call_prepare_ice(call,FALSE); + if (err==1) { + ms_message("Defer call update to gather ICE candidates"); + return 0; + } #ifdef VIDEO_ENABLED // Video adding if (!has_video && call->params.has_video) { - if (call->ice_session != NULL) { - /* Defer call update until the ICE candidates gathering process has finished. */ - ms_message("Defer call update to gather ICE candidates"); - linphone_call_init_video_stream(call); - video_stream_prepare_video(call->videostream); - if (linphone_core_gather_ice_candidates(lc,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - } else { - return err; - } - } #ifdef BUILD_UPNP if(call->upnp_session != NULL) { ms_message("Defer call update to add uPnP port mappings"); - linphone_call_init_video_stream(call); video_stream_prepare_video(call->videostream); if (linphone_core_update_upnp(lc, call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ @@ -3202,7 +3180,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho } #endif //BUILD_UPNP } -#endif +#endif //VIDEO_ENABLED err = linphone_core_start_update_call(lc, call); }else{ #ifdef VIDEO_ENABLED @@ -3248,13 +3226,9 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) /* Defer the sending of the answer until there are no losing pairs left. */ return 0; } - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); } -#ifdef BUILD_UPNP - if(call->upnp_session != NULL) { - linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); - } -#endif //BUILD_UPNP + linphone_call_make_local_media_description(lc,call); + linphone_call_update_remote_session_id_and_ver(call); sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); @@ -3328,20 +3302,9 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons } call->params.has_video &= linphone_core_media_description_contains_video_stream(remote_desc); linphone_call_init_media_streams(call); /*so that video stream is initialized if necessary*/ - linphone_call_make_local_media_description(lc,call); if (call->ice_session != NULL) { - linphone_core_update_ice_from_remote_media_description(call, remote_desc); -#ifdef VIDEO_ENABLED - if ((call->ice_session != NULL) && !ice_session_candidates_gathered(call->ice_session)) { - if ((call->params.has_video) && (call->params.has_video != old_has_video)) { - video_stream_prepare_video(call->videostream); - if (linphone_core_gather_ice_candidates(lc,call)<0) { - /* Ice candidates gathering failed, proceed with the call anyway. */ - linphone_call_delete_ice_session(call); - } else return 0; - } - } -#endif //VIDEO_ENABLED + if (linphone_call_prepare_ice(call,TRUE)==1) + return 0;/*deferred to completion of ICE gathering*/ } #ifdef BUILD_UPNP @@ -3665,9 +3628,6 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) return -1; } linphone_call_make_local_media_description(lc,call); - if (call->ice_session != NULL) { - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); - } #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); @@ -3761,9 +3721,6 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){ if (call->audiostream) audio_stream_play(call->audiostream, NULL); linphone_call_make_local_media_description(lc,call); - if (call->ice_session != NULL) { - linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session); - } #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); diff --git a/coreapi/private.h b/coreapi/private.h index 69ca8c728..45dc5f305 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -804,6 +804,7 @@ bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); const char *linphone_core_create_uuid(LinphoneCore *lc); void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact); void linphone_call_create_op(LinphoneCall *call); +int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer); void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body); LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref); SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc); From 43aa6ef34f33962fc2b583906d75139af213d88a Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 17 Apr 2014 16:22:43 +0200 Subject: [PATCH 431/439] change encryption state management --- coreapi/bellesip_sal/sal_sdp.c | 20 +-- coreapi/linphonecall.c | 74 ++++++----- coreapi/private.h | 2 - include/sal/sal.h | 5 +- mediastreamer2 | 2 +- oRTP | 2 +- tester/call_tester.c | 232 ++++++++++++++++++++++----------- tester/liblinphone_tester.h | 4 + tester/tester.c | 1 + 9 files changed, 210 insertions(+), 132 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 2c9411841..0ee29e6da 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -149,22 +149,22 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session const char *enc_name=NULL; switch ( stream->crypto[j].algo ) { - case AES_128_SHA1_80: + case MS_AES_128_SHA1_80: enc_name="AES_CM_128_HMAC_SHA1_80"; break; - case AES_128_SHA1_32: + case MS_AES_128_SHA1_32: enc_name="AES_CM_128_HMAC_SHA1_32"; break; - case AES_256_SHA1_32: + case MS_AES_256_SHA1_32: enc_name="AES_CM_256_HMAC_SHA1_32"; break; - case AES_256_SHA1_80: + case MS_AES_256_SHA1_80: enc_name="AES_CM_256_HMAC_SHA1_32"; break; - case AES_128_NO_AUTH: + case MS_AES_128_NO_AUTH: ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" ); break; - case NO_CIPHER_SHA1_80: + case MS_NO_CIPHER_SHA1_80: ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" ); break; default: @@ -351,13 +351,13 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med tmp2 ); if ( nb == 3 ) { if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ){ - stream->crypto[valid_count].algo = AES_128_SHA1_80; + stream->crypto[valid_count].algo = MS_AES_128_SHA1_80; }else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 ){ - stream->crypto[valid_count].algo = AES_128_SHA1_32; + stream->crypto[valid_count].algo = MS_AES_128_SHA1_32; }else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_32",tmp ) == 0 ){ - stream->crypto[valid_count].algo = AES_256_SHA1_32; + stream->crypto[valid_count].algo = MS_AES_256_SHA1_32; }else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_80",tmp ) == 0 ){ - stream->crypto[valid_count].algo = AES_256_SHA1_80; + stream->crypto[valid_count].algo = MS_AES_256_SHA1_80; }else { ms_warning ( "Failed to parse crypto-algo: '%s'", tmp ); stream->crypto[valid_count].algo = 0; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index eb4a00551..eda356c05 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -95,22 +95,21 @@ bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){ } static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) { - // Check ZRTP encryption in audiostream - if (!call->audiostream_encrypted) { - return FALSE; - } - -#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; + int number_of_encrypted_stream = 0; + int number_of_active_stream = 0; + if (call) { + if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { + number_of_active_stream++; + if(media_stream_is_secured((MediaStream *)call->audiostream)) + number_of_encrypted_stream++; + } + if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + number_of_active_stream++; + if (media_stream_is_secured((MediaStream *)call->videostream)) + number_of_encrypted_stream++; } } -#endif - - return TRUE; + return number_of_active_stream>0 & number_of_active_stream==number_of_encrypted_stream; } void propagate_encryption_changed(LinphoneCall *call){ @@ -131,9 +130,6 @@ void propagate_encryption_changed(LinphoneCall *call){ #ifdef VIDEO_ENABLED static void linphone_call_videostream_encryption_changed(void *data, bool_t encrypted){ LinphoneCall *call = (LinphoneCall *)data; - - ms_message("Video stream is %s", encrypted ? "encrypted" : "not encrypted"); - call->videostream_encrypted=encrypted; propagate_encryption_changed(call); } #endif @@ -141,10 +137,8 @@ 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"); call = (LinphoneCall *)data; - call->audiostream_encrypted=encrypted; if (encrypted && call->core->vtable.display_status != NULL) { snprintf(status,sizeof(status)-1,_("Authentication token is %s"),call->auth_token); @@ -260,11 +254,11 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ } }else{ md->streams[i].crypto[0].tag = 1; - md->streams[i].crypto[0].algo = AES_128_SHA1_80; + md->streams[i].crypto[0].algo = MS_AES_128_SHA1_80; if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key, SAL_SRTP_KEY_SIZE)) md->streams[i].crypto[0].algo = 0; md->streams[i].crypto[1].tag = 2; - md->streams[i].crypto[1].algo = AES_128_SHA1_32; + md->streams[i].crypto[1].algo = MS_AES_128_SHA1_32; if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key, SAL_SRTP_KEY_SIZE)) md->streams[i].crypto[1].algo = 0; md->streams[i].crypto[2].algo = 0; @@ -482,6 +476,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->log=linphone_call_log_new(call, from, to); call->owns_call_log=TRUE; call->camera_enabled=TRUE; + call->current_params.media_encryption=LinphoneMediaEncryptionNone; linphone_core_get_audio_port_range(call->core, &min_port, &max_port); port_config_set(call,0,min_port,max_port); @@ -916,6 +911,16 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ } #endif + if (linphone_call_are_all_streams_encrypted(call)) { + if (linphone_call_get_authentication_token(call)) { + call->current_params.media_encryption=LinphoneMediaEncryptionZRTP; + } else { + call->current_params.media_encryption=LinphoneMediaEncryptionSRTP; + } + } else { + call->current_params.media_encryption=LinphoneMediaEncryptionNone; + } + return &call->current_params; } @@ -1903,12 +1908,10 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna if (crypto_idx >= 0) { media_stream_set_srtp_recv_key(&call->audiostream->ms,stream->crypto[0].algo,stream->crypto[0].master_key); media_stream_set_srtp_send_key(&call->audiostream->ms,stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); - call->audiostream_encrypted=TRUE; } else { ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag); - call->audiostream_encrypted=FALSE; } - }else call->audiostream_encrypted=FALSE; + } configure_rtp_session_for_rtcp_xr(lc, call, SalAudio); audio_stream_start_full( call->audiostream, @@ -2022,14 +2025,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna if (!is_inactive){ if (vstream->proto == SalProtoRtpSavp) { int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag); - if (crypto_idx >= 0) { media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key); media_stream_set_srtp_send_key(&call->videostream->ms,vstream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); - call->videostream_encrypted=TRUE; - }else call->videostream_encrypted=FALSE; - }else{ - call->videostream_encrypted=FALSE; + } } configure_rtp_session_for_rtcp_xr(lc, call, SalVideo); @@ -2090,11 +2089,17 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut if (call->params.media_encryption==LinphoneMediaEncryptionZRTP) { OrtpZrtpParams params; - /*will be set later when zrtp is activated*/ - call->current_params.media_encryption=LinphoneMediaEncryptionNone; - + memset(¶ms,0,sizeof(OrtpZrtpParams)); + /*call->current_params.media_encryption will be set later when zrtp is activated*/ params.zid_file=lc->zrtp_secrets_cache; audio_stream_enable_zrtp(call->audiostream,¶ms); +#if VIDEO_ENABLED + if (media_stream_is_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + /*audio stream is already encrypted and video stream is active*/ + memset(¶ms,0,sizeof(OrtpZrtpParams)); + video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms); + } +#endif }else{ call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ? LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; @@ -2144,8 +2149,7 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio); if (call->audiostream && local_st_desc && old_stream && new_stream && update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){ - call->audiostream_encrypted = TRUE; - }else call->audiostream_encrypted = FALSE; + } #ifdef VIDEO_ENABLED local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo); @@ -2153,9 +2157,7 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo); if (call->videostream && local_st_desc && old_stream && new_stream && update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){ - call->videostream_encrypted = TRUE; } - call->videostream_encrypted = FALSE; #endif } diff --git a/coreapi/private.h b/coreapi/private.h index 45dc5f305..6634a3344 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -224,8 +224,6 @@ struct _LinphoneCall bool_t owns_call_log; bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/ - bool_t videostream_encrypted; - bool_t audiostream_encrypted; bool_t auth_token_verified; bool_t defer_update; diff --git a/include/sal/sal.h b/include/sal/sal.h index 1dba31f90..d0215c89c 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -30,9 +30,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "config.h" #endif -#include "mediastreamer2/mscommon.h" +#include "mediastreamer2/mediastream.h" #include "ortp/rtpsession.h" -#include "ortp/ortp_srtp.h" #include "belle-sip/belle-sip.h" #ifndef LINPHONE_PUBLIC @@ -171,7 +170,7 @@ typedef struct SalIceRemoteCandidate { typedef struct SalSrtpCryptoAlgo { unsigned int tag; - enum ortp_srtp_crypto_suite_t algo; + MSCryptoSuite algo; char master_key[SAL_SRTP_KEY_SIZE]; } SalSrtpCryptoAlgo; diff --git a/mediastreamer2 b/mediastreamer2 index 41db9323b..5363f6d64 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 41db9323be6a6d136949ee5fdba1198c38a7d787 +Subproject commit 5363f6d6487f44c0fa898647b7b859857db13283 diff --git a/oRTP b/oRTP index beee1f20d..891f3da68 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit beee1f20d69af3d04cd27fcc00b3830620066367 +Subproject commit 891f3da6817e30b606493840f305250f81a254bd diff --git a/tester/call_tester.c b/tester/call_tester.c index 3e8ef9475..067292942 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -24,6 +24,7 @@ #include "private.h" #include "liblinphone_tester.h" +static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy); 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); @@ -59,7 +60,22 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState CU_FAIL("unexpected event");break; } } - +void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token) { + char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); + char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); + stats* counters; + ms_message(" %s call from [%s] to [%s], is now [%s]",linphone_call_get_call_log(call)->dir==LinphoneCallIncoming?"Incoming":"Outgoing" + ,from + ,to + ,(on?"encrypted":"unencrypted")); + ms_free(to); + ms_free(from); + counters = get_stats(lc); + if (on) + counters->number_of_LinphoneCallEncryptedOn++; + else + counters->number_of_LinphoneCallEncryptedOff++; +} void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from); @@ -198,12 +214,19 @@ bool_t call_with_params(LinphoneCoreManager* caller_mgr && 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)) { + if (linphone_core_get_media_encryption(caller_mgr->lc) != LinphoneMediaEncryptionNone + && linphone_core_get_media_encryption(callee_mgr->lc) != LinphoneMediaEncryptionNone) { + /*wait for encryption to be on, in case of zrtp, it can take a few seconds*/ + if (linphone_core_get_media_encryption(caller_mgr->lc) == LinphoneMediaEncryptionZRTP) + wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_caller.number_of_LinphoneCallEncryptedOn+1); + if (linphone_core_get_media_encryption(callee_mgr->lc) == LinphoneMediaEncryptionZRTP) + wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallEncryptedOn,initial_callee.number_of_LinphoneCallEncryptedOn+1); + { const LinphoneCallParams* call_param = linphone_call_get_current_params(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; } @@ -516,6 +539,17 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee } ms_usleep(50000); } + + /*make sure encryption mode are preserved*/ + if (c1) { + const LinphoneCallParams* call_param = linphone_call_get_current_params(c1); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc)); + } + if (c2) { + const LinphoneCallParams* call_param = linphone_call_get_current_params(c2); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(callee->lc)); + } + return success; } @@ -703,6 +737,15 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) LinphoneVideoPolicy caller_policy; LinphoneCallParams* callee_params; LinphoneCall* call_obj; + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + + if (linphone_call_get_state(linphone_core_get_current_call(callee->lc)) != LinphoneCallStreamsRunning + || linphone_call_get_state(linphone_core_get_current_call(caller->lc)) != LinphoneCallStreamsRunning ) { + ms_warning("bad state for adding video"); + return FALSE; + } + caller_policy.automatically_accept=TRUE; caller_policy.automatically_initiate=TRUE; linphone_core_enable_video_capture(callee->lc, TRUE); @@ -710,8 +753,8 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) 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; + + if ((call_obj = linphone_core_get_current_call(callee->lc))) { callee_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj)); @@ -726,6 +769,21 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) 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)))); + if (linphone_core_get_media_encryption(caller->lc) != LinphoneMediaEncryptionNone + && linphone_core_get_media_encryption(callee->lc) != LinphoneMediaEncryptionNone) { + /*wait for encryption to be on, in case of zrtp, it can take a few seconds*/ + if (linphone_core_get_media_encryption(caller->lc) == LinphoneMediaEncryptionZRTP) + wait_for(callee->lc,caller->lc,&caller->stat.number_of_LinphoneCallEncryptedOn,initial_caller_stat.number_of_LinphoneCallEncryptedOn+1); + if (linphone_core_get_media_encryption(callee->lc) == LinphoneMediaEncryptionZRTP) + wait_for(callee->lc,caller->lc,&callee->stat.number_of_LinphoneCallEncryptedOn,initial_callee_stat.number_of_LinphoneCallEncryptedOn+1); + + { + const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc)); + call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller->lc)); + } + } linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,callee->lc); /*send vfu*/ @@ -824,19 +882,21 @@ static void video_call(void) { 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))); + if (marie_call && pauline_call ) { + CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); + CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call))); - /*check video path*/ - linphone_call_set_next_video_frame_decoded_callback(marie_call,linphone_call_cb,marie->lc); - linphone_call_send_vfu_request(marie_call); - CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1)); + /*check 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)); - liblinphone_tester_check_rtcp(marie,pauline); + liblinphone_tester_check_rtcp(marie,pauline); - linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + linphone_core_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); @@ -1139,45 +1199,17 @@ static void simple_conference(void) { } -static void encrypted_call(LinphoneMediaEncryption mode) { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - - if (linphone_core_media_encryption_supported(marie->lc,mode)) { - linphone_core_set_media_encryption(marie->lc,mode); - linphone_core_set_media_encryption(pauline->lc,mode); - - CU_ASSERT_TRUE(call(pauline,marie)); - - CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),mode); - CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),mode); - if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP - && linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) { - /*check SAS*/ - CU_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) - ,linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))); - } - liblinphone_tester_check_rtcp(pauline,marie); - /*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 %s not available", linphone_media_encryption_to_string(mode)); - } - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} static void srtp_call() { - encrypted_call(LinphoneMediaEncryptionSRTP); + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyNoFirewall); } -/* - * future work static void zrtp_call() { - encrypted_call(LinphoneMediaEncryptionZRTP); -}*/ + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyNoFirewall); +} +static void zrtp_video_call() { + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyNoFirewall); +} static void call_with_declined_srtp(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); @@ -1197,43 +1229,70 @@ static void call_with_declined_srtp(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } -#ifdef VIDEO_ENABLED -static void srtp_video_ice_call(void) { + +static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy) { int i=0; -#else -static void srtp_ice_call(void) { -#endif LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + if (enable_relay) { + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + } + if (linphone_core_media_encryption_supported(marie->lc,mode)) { + linphone_core_set_media_encryption(marie->lc,mode); + linphone_core_set_media_encryption(pauline->lc,mode); - if (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_firewall_policy(marie->lc,policy); linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); - linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_firewall_policy(pauline->lc,policy); linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); CU_ASSERT_TRUE(call(pauline,marie)); + if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP + && linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) { + /*wait for SAS*/ + int i; + for (i=0;i<10;i++) { + if (linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) + && + linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))) { + /*check SAS*/ + CU_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) + ,linphone_call_get_authentication_token(linphone_core_get_current_call(marie->lc))); + liblinphone_tester_check_rtcp(pauline,marie); + break; + } + linphone_core_iterate(marie->lc); + linphone_core_iterate(pauline->lc); + ms_usleep(200000); + } - 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); + if (policy == LinphonePolicyUseIce) + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + if (enable_video) { + if (linphone_core_video_supported(marie->lc)) { + 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); + if (policy == LinphonePolicyUseIce) + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + + liblinphone_tester_check_rtcp(marie,pauline); + /*wait for ice to found the direct path*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); + } else { + ms_warning ("not tested because video not available"); + } + + } - CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); - liblinphone_tester_check_rtcp(marie,pauline); - /*wait for ice to found the direct path*/ - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); -#endif - /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); @@ -1246,9 +1305,21 @@ static void srtp_ice_call(void) { linphone_core_manager_destroy(pauline); } - - - +static void srtp_video_ice_call(void) { + call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce); +} +static void srtp_ice_call(void) { + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce); +} +static void zrtp_video_ice_call(void) { + /*encrypted_ice_call(LinphoneMediaEncryptionZRTP,TRUE,FALSE);*/ +} +static void zrtp_ice_call(void) { + /*encrypted_ice_call(LinphoneMediaEncryptionZRTP,FALSE,FALSE);*/ +} +static void zrtp_ice_call_with_relay(void) { + /*encrypted_ice_call(LinphoneMediaEncryptionZRTP,FALSE,TRUE);*/ +} static void early_media_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_early_rc"); @@ -1901,17 +1972,20 @@ test_t call_tests[] = { { "Call paused resumed", call_paused_resumed }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, { "SRTP call", srtp_call }, - /*{ "ZRTP call",zrtp_call}, futur work*/ + { "ZRTP call",zrtp_call}, + { "ZRTP video call",zrtp_video_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 }, + { "ZRTP ice video call", zrtp_video_ice_call }, { "Call with video added", call_with_video_added }, { "Call with video added (random ports)", call_with_video_added_random_ports }, { "Call with video declined",call_with_declined_video}, -#else - { "SRTP ice call", srtp_ice_call }, #endif + { "SRTP ice call", srtp_ice_call }, + { "ZRTP ice call", zrtp_ice_call }, + { "ZRTP ice call with relay", zrtp_ice_call_with_relay}, { "Call with privacy", call_with_privacy }, { "Call with privacy 2", call_with_privacy2 }, { "Call rejected because of wrong credential", call_rejected_because_wrong_credentials}, diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index d9dc9b914..5e5767bab 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -181,6 +181,9 @@ typedef struct _stats { int number_of_LinphoneConfiguringSkipped; int number_of_LinphoneConfiguringFailed; int number_of_LinphoneConfiguringSuccessful; + + int number_of_LinphoneCallEncryptedOn; + int number_of_LinphoneCallEncryptedOff; }stats; typedef struct _LinphoneCoreManager { @@ -212,6 +215,7 @@ void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, Lin void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state); void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content); void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message); +void linphone_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token); LinphoneAddress * create_linphone_address(const char * domain); bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value); diff --git a/tester/tester.c b/tester/tester.c index caeb78009..2d734b074 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -205,6 +205,7 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->v_table.notify_received=linphone_notify_received; mgr->v_table.publish_state_changed=linphone_publish_state_changed; mgr->v_table.configuring_status=linphone_configuration_status; + mgr->v_table.call_encryption_changed=linphone_call_encryption_changed; reset_counters(&mgr->stat); if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file); From 471314ee1a30e110e061b7d76e00c6c224ff07a5 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 18 Apr 2014 09:06:11 +0200 Subject: [PATCH 432/439] preserve media encryption mode for zrtp in case of re-invite initiated by ice --- coreapi/linphonecall.c | 10 ++++++++-- mediastreamer2 | 2 +- oRTP | 2 +- tester/call_tester.c | 6 +++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index eda356c05..37d853ef3 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2639,11 +2639,17 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ int ping_time; if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) { + LinphoneCallParams params; + _linphone_call_params_copy(¶ms,&call->current_params); + if (call->params.media_encryption == LinphoneMediaEncryptionZRTP) { + /* preserve media encryption param because at that time ZRTP negociation may still be ongoing*/ + params.media_encryption=call->params.media_encryption; + } switch (ice_session_state(call->ice_session)) { case IS_Completed: ice_session_select_candidates(call->ice_session); if (ice_session_role(call->ice_session) == IR_Controlling) { - linphone_core_update_call(call->core, call, &call->current_params); + linphone_core_update_call(call->core, call, ¶ms); } break; case IS_Failed: @@ -2651,7 +2657,7 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ ice_session_select_candidates(call->ice_session); if (ice_session_role(call->ice_session) == IR_Controlling) { /* At least one ICE session has succeeded, so perform a call update. */ - linphone_core_update_call(call->core, call, &call->current_params); + linphone_core_update_call(call->core, call, ¶ms); } } break; diff --git a/mediastreamer2 b/mediastreamer2 index 5363f6d64..86110766b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5363f6d6487f44c0fa898647b7b859857db13283 +Subproject commit 86110766b0cfbd0ecfd4ab853715e0c3d681385b diff --git a/oRTP b/oRTP index 891f3da68..c09e63ddb 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 891f3da6817e30b606493840f305250f81a254bd +Subproject commit c09e63ddba599a7f7da149edf6f7b290f4cfa787 diff --git a/tester/call_tester.c b/tester/call_tester.c index 067292942..924b08950 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1312,13 +1312,13 @@ static void srtp_ice_call(void) { call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce); } static void zrtp_video_ice_call(void) { - /*encrypted_ice_call(LinphoneMediaEncryptionZRTP,TRUE,FALSE);*/ + call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce); } static void zrtp_ice_call(void) { - /*encrypted_ice_call(LinphoneMediaEncryptionZRTP,FALSE,FALSE);*/ + call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce); } static void zrtp_ice_call_with_relay(void) { - /*encrypted_ice_call(LinphoneMediaEncryptionZRTP,FALSE,TRUE);*/ + call_base(LinphoneMediaEncryptionZRTP,FALSE,TRUE,LinphonePolicyUseIce); } static void early_media_call(void) { From d6fef910bb543235844d6069ed3d13fa561cbd97 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 18 Apr 2014 11:02:09 +0200 Subject: [PATCH 433/439] fix crash with ICE and compilation error --- coreapi/linphonecall.c | 8 ++++---- tester/call_tester.c | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 37d853ef3..8167f2425 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -109,10 +109,10 @@ static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) { number_of_encrypted_stream++; } } - return number_of_active_stream>0 & number_of_active_stream==number_of_encrypted_stream; + return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream; } -void propagate_encryption_changed(LinphoneCall *call){ +static void propagate_encryption_changed(LinphoneCall *call){ LinphoneCore *lc=call->core; if (!linphone_call_are_all_streams_encrypted(call)) { ms_message("Some streams are not encrypted"); @@ -1462,8 +1462,8 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ if (has_video) _linphone_call_prepare_ice_for_stream(call,1,TRUE); /*start ICE gathering*/ if (incoming_offer) - linphone_core_update_ice_from_remote_media_description(call,remote); - if (!ice_session_candidates_gathered(call->ice_session)){ + linphone_core_update_ice_from_remote_media_description(call,remote); /*this may delete the ice session*/ + if (call->ice_session && !ice_session_candidates_gathered(call->ice_session)){ if (call->audiostream->ms.state==MSStreamInitialized) audio_stream_prepare_sound(call->audiostream, NULL, NULL); #ifdef VIDEO_ENABLED diff --git a/tester/call_tester.c b/tester/call_tester.c index 924b08950..1616ae649 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -553,14 +553,18 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee return success; } -static void _call_with_ice(bool_t random_ports) { +static void _call_with_ice(bool_t caller_with_ice, bool_t callee_with_ice, bool_t random_ports) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); - linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); - linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); - linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + if (callee_with_ice){ + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); + } + if (caller_with_ice){ + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + } if (random_ports){ linphone_core_set_audio_port(marie->lc,-1); @@ -571,12 +575,14 @@ static void _call_with_ice(bool_t random_ports) { 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)); + if (callee_with_ice && caller_with_ice) { + 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)); - CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + } liblinphone_tester_check_rtcp(marie,pauline); /*then close the call*/ @@ -589,11 +595,19 @@ static void _call_with_ice(bool_t random_ports) { } static void call_with_ice(void){ - _call_with_ice(FALSE); + _call_with_ice(TRUE,TRUE,FALSE); } static void call_with_ice_random_ports(void){ - _call_with_ice(TRUE); + _call_with_ice(TRUE,TRUE,TRUE); +} + +static void ice_to_not_ice(void){ + _call_with_ice(TRUE,FALSE,FALSE); +} + +static void not_ice_to_ice(void){ + _call_with_ice(FALSE,TRUE,FALSE); } static void call_with_custom_headers(void) { @@ -2000,6 +2014,8 @@ test_t call_tests[] = { { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, { "Call with ICE", call_with_ice }, { "Call with ICE (random ports)", call_with_ice_random_ports }, + { "Call from ICE to not ICE",ice_to_not_ice}, + { "Call from not ICE to ICE",not_ice_to_ice}, { "Call with custom headers",call_with_custom_headers}, { "Call established with rejected INFO",call_established_with_rejected_info}, { "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite}, From ce7a483183be66062d6a8cd3479e61c802c867f7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 18 Apr 2014 11:15:13 +0200 Subject: [PATCH 434/439] Fix local remote provisioning test for android --- tester/rcfiles/marie_remote_localfile_android_rc | 3 +++ tester/remote_provisioning_tester.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tester/rcfiles/marie_remote_localfile_android_rc diff --git a/tester/rcfiles/marie_remote_localfile_android_rc b/tester/rcfiles/marie_remote_localfile_android_rc new file mode 100644 index 000000000..ef0a321ce --- /dev/null +++ b/tester/rcfiles/marie_remote_localfile_android_rc @@ -0,0 +1,3 @@ +[misc] +config-uri=file:///data/data/org.linphone.tester/files/config_files/rcfiles/marie_remote_localfile2_rc + diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 99bfbcc6a..365673ff6 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -90,8 +90,13 @@ static void remote_provisioning_default_values(void) { } static void remote_provisioning_file(void) { - LinphoneCoreManager* marie = linphone_core_manager_new2("marie_remote_localfile_rc", FALSE); + LinphoneCoreManager* marie; const LpConfig* conf; +#if ANDROID + marie = linphone_core_manager_new2("marie_remote_localfile_android_rc", FALSE); +#else + marie = linphone_core_manager_new2("marie_remote_localfile_rc", FALSE); +#endif CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphoneConfiguringSuccessful,1)); conf = linphone_core_get_config( marie->lc ); From 62365a41199da5e0c1e2685c0082f873a2e7ec85 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 18 Apr 2014 11:20:26 +0200 Subject: [PATCH 435/439] Fix compil of tester for android --- tester/call_tester.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tester/call_tester.c b/tester/call_tester.c index 1616ae649..928ce6484 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1286,6 +1286,7 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e if (policy == LinphonePolicyUseIce) CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); +#ifdef VIDEO_ENABLED if (enable_video) { if (linphone_core_video_supported(marie->lc)) { for (i=0;i<100;i++) { /*fixme to workaround a crash*/ @@ -1306,6 +1307,7 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e } } +#endif /*just to sleep*/ From 9f68674a4b10aa6a6907cebf65b941997719e9e7 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 18 Apr 2014 11:36:06 +0200 Subject: [PATCH 436/439] ms2:fix opus traces --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 86110766b..a66959cdc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 86110766b0cfbd0ecfd4ab853715e0c3d681385b +Subproject commit a66959cdc9ffa2eb2736c465dfe942ce8a74dbda From c1ef06eb8f2a7c88d6e54943930a838085d11e9e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 18 Apr 2014 16:05:04 +0200 Subject: [PATCH 437/439] add refcounting to LpConfig --- coreapi/linphonecore.c | 7 +++++-- coreapi/lpconfig.c | 21 +++++++++++++++++++-- coreapi/lpconfig.h | 19 ++++++++++++++++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bd852968e..bc52d67fa 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1304,7 +1304,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab const char *remote_provisioning_uri = NULL; ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); memset (lc, 0, sizeof (LinphoneCore)); - lc->config=config; + lc->config=lp_config_ref(config); lc->data=userdata; lc->ringstream_autorelease=TRUE; @@ -1421,8 +1421,11 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config_path, void * userdata) { + LinphoneCore *lc; LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path); - return linphone_core_new_with_config(vtable, config, userdata); + lc=linphone_core_new_with_config(vtable, config, userdata); + lp_config_unref(config); + return lc; } LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata) diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 6e51d257c..d6ccea612 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -63,6 +63,7 @@ typedef struct _LpSection{ } LpSection; struct _LpConfig{ + int refcnt; FILE *file; char *filename; MSList *sections; @@ -287,6 +288,7 @@ LpConfig * lp_config_new(const char *filename){ LpConfig * lp_config_new_from_buffer(const char *buffer){ LpConfig* conf = lp_new0(LpConfig,1); + conf->refcnt=1; LpSection* current_section = NULL; char* ptr = ms_strdup(buffer); @@ -305,7 +307,7 @@ LpConfig * lp_config_new_from_buffer(const char *buffer){ LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) { LpConfig *lpconfig=lp_new0(LpConfig,1); - + lpconfig->refcnt=1; if (config_filename!=NULL){ ms_message("Using (r/w) config information from %s", config_filename); lpconfig->filename=ortp_strdup(config_filename); @@ -354,13 +356,28 @@ void lp_item_set_value(LpItem *item, const char *value){ } -void lp_config_destroy(LpConfig *lpconfig){ +static void _lp_config_destroy(LpConfig *lpconfig){ if (lpconfig->filename!=NULL) ortp_free(lpconfig->filename); ms_list_for_each(lpconfig->sections,(void (*)(void*))lp_section_destroy); ms_list_free(lpconfig->sections); free(lpconfig); } +LpConfig *lp_config_ref(LpConfig *lpconfig){ + lpconfig->refcnt++; + return lpconfig; +} + +void lp_config_unref(LpConfig *lpconfig){ + lpconfig->refcnt--; + if (lpconfig->refcnt==0) + _lp_config_destroy(lpconfig); +} + +void lp_config_destroy(LpConfig *lpconfig){ + lp_config_unref(lpconfig); +} + void lp_section_remove_item(LpSection *sec, LpItem *item){ sec->items=ms_list_remove(sec->items,(void *)item); lp_item_destroy(item); diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index f0f330c18..bd229803e 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -57,7 +57,7 @@ extern "C" { /** * Instantiates a LpConfig object from a user config file. - * + * The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed. * @ingroup misc * @param filename the filename of the config file to read to fill the instantiated LpConfig * @see lp_config_new_with_factory @@ -66,7 +66,7 @@ LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename); /** * Instantiates a LpConfig object from a user provided buffer. - * + * The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed. * @ingroup misc * @param buffer the buffer from which the lpconfig will be retrieved. We expect the buffer to be null-terminated. * @see lp_config_new_with_factory @@ -76,7 +76,7 @@ LINPHONE_PUBLIC LpConfig * lp_config_new_from_buffer(const char *buffer); /** * Instantiates a LpConfig object from a user config file and a factory config file. - * + * The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed. * @ingroup misc * @param config_filename the filename of the user config file to read to fill the instantiated LpConfig * @param factory_config_filename the filename of the factory config file to read to fill the instantiated LpConfig @@ -259,6 +259,19 @@ LINPHONE_PUBLIC const char* lp_config_get_default_string(const LpConfig *lpconfi **/ LINPHONE_PUBLIC const char* lp_config_get_section_param_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value); + +/** + * increment reference count + * @ingroup misc +**/ +LINPHONE_PUBLIC LpConfig *lp_config_ref(LpConfig *lpconfig); + +/** + * Decrement reference count, which will eventually free the object. + * @ingroup misc +**/ +LINPHONE_PUBLIC void lp_config_unref(LpConfig *lpconfig); + #ifdef __cplusplus } #endif From e0ee323dd02febc94511f6546085c330bbe47d1c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 21 Apr 2014 10:27:18 +0200 Subject: [PATCH 438/439] give more time in tests --- README.mingw | 10 +++++++++- tester/flexisip_tester.c | 18 +++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/README.mingw b/README.mingw index 9e9e78075..79e8ce547 100644 --- a/README.mingw +++ b/README.mingw @@ -118,8 +118,8 @@ linphone-deps packages. List of software included in linphone-deps: antlr3c (compiled) +bzrtp (compiled) polarssl (compiled -belle-sip (compiled) libsrtp (compiled) libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all these from ffmpeg) libtheora (from the web) @@ -167,6 +167,14 @@ When running "make install DESTDIR=", somepath must be absolute and sh $ make install $ make install DESTDIR=/home//libsrtp-install +- building bzrtp + * download the sources with msys-git shell using the following command: + $ git clone git://git.linphone.org/bzrtp.git + * compile and install + $ ./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + $ make && make install + - building sqlite3 * download the sources on the following website: http://www.sqlite.org/download.html (choose the sqlite-autoconf-3XXX.tar.gz) diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 4218c1009..1a75cdd97 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -43,7 +43,7 @@ static void subscribe_forking(void) { lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,&content); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline2->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000)); @@ -71,7 +71,7 @@ static void message_forking(void) { lcs=ms_list_append(lcs,marie2->lc); linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneMessageReceived,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,1000)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); @@ -101,7 +101,7 @@ static void message_forking_with_unreachable_recipients(void) { linphone_core_set_network_reachable(marie3->lc,FALSE); linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneMessageReceived,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneMessageDelivered,1,1000)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); CU_ASSERT_TRUE( marie2->stat.number_of_LinphoneMessageReceived==0); @@ -192,7 +192,7 @@ static void call_forking(void){ linphone_core_invite_address(pauline->lc,marie->identity); /*pauline should hear ringback*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); /*all devices from Marie should be ringing*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); @@ -400,7 +400,7 @@ static void call_forking_with_push_notification_single(void){ linphone_core_set_network_reachable(marie->lc,TRUE); /*Marie shall receive the call immediately*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,5000)); /*pauline should hear ringback as well*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); @@ -450,7 +450,7 @@ static void call_forking_with_push_notification_multiple(void){ linphone_core_invite_address(pauline->lc,marie->identity); /*marie1 will ring*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,5000)); /*pauline should hear ringback as well*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); @@ -458,7 +458,7 @@ static void call_forking_with_push_notification_multiple(void){ linphone_core_set_network_reachable(marie2->lc,TRUE); /*Marie shall receive the call immediately*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,5000)); /*marie2 accepts the call*/ linphone_core_accept_call(marie2->lc,linphone_core_get_current_call(marie2->lc)); @@ -500,7 +500,7 @@ void call_forking_not_responded(void){ linphone_core_invite_address(pauline->lc,marie->identity); /*pauline should hear ringback*/ - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); /*all devices from Marie should be ringing*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,1000)); @@ -568,7 +568,7 @@ static void early_media_call_forking(void) { 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, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); 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)); From b74aa1f56a6c209e9679cb40431892189fcb722c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 21 Apr 2014 10:35:47 +0200 Subject: [PATCH 439/439] fix audio-only build --- coreapi/linphonecore.c | 2 +- tester/call_tester.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bc52d67fa..dbd8eb07a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3277,7 +3277,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ SalMediaDescription *remote_desc; bool_t keep_sdp_version; -#ifdef VIDEO_ENABLED +#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) bool_t old_has_video = call->params.has_video; #endif diff --git a/tester/call_tester.c b/tester/call_tester.c index 928ce6484..facec8769 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1245,7 +1245,6 @@ static void call_with_declined_srtp(void) { } static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy) { - int i=0; LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); if (enable_relay) { @@ -1288,6 +1287,7 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); #ifdef VIDEO_ENABLED if (enable_video) { + int i=0; if (linphone_core_video_supported(marie->lc)) { for (i=0;i<100;i++) { /*fixme to workaround a crash*/ ms_usleep(20000); @@ -1321,15 +1321,19 @@ static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t e linphone_core_manager_destroy(pauline); } +#ifdef VIDEO_ENABLED static void srtp_video_ice_call(void) { call_base(LinphoneMediaEncryptionSRTP,TRUE,FALSE,LinphonePolicyUseIce); } -static void srtp_ice_call(void) { - call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce); -} static void zrtp_video_ice_call(void) { call_base(LinphoneMediaEncryptionZRTP,TRUE,FALSE,LinphonePolicyUseIce); } +#endif + +static void srtp_ice_call(void) { + call_base(LinphoneMediaEncryptionSRTP,FALSE,FALSE,LinphonePolicyUseIce); +} + static void zrtp_ice_call(void) { call_base(LinphoneMediaEncryptionZRTP,FALSE,FALSE,LinphonePolicyUseIce); }