diff --git a/.cproject b/.cproject index d4a5780c3..51c77f8e9 100644 --- a/.cproject +++ b/.cproject @@ -22,7 +22,7 @@ - + diff --git a/.gitignore b/.gitignore index 9dd415435..0512fc3df 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,19 @@ coreapi/test_ecc coreapi/test_lsd gtk/version_date.h specs.c +*.orig +*.rej +*.kdev4 +*.lo +*.la +*.swp +.deps +.libs +coreapi/test_numbers +coreapi/help/notify +share/fresh-rootca.pem +share/certdata.txt +tester/liblinphone_tester +tools/lp-gen-wrappers +tools/lpc2xml_test +tools/xml2lpc_test diff --git a/README b/README index 0efd14949..8913f1205 100644 --- a/README +++ b/README @@ -10,6 +10,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. - you need at least: - belle-sip>=1.0.0 - speex>=1.2.0 (including libspeexdsp part) + - libxml2 + if you want the gtk/glade interface: - libgtk >=2.16.0 @@ -32,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 libvx-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev + $ sudo apt-get install libtool intltool libgtk2.0-dev libosip2-dev libexosip2-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libxv-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev libxml2-dev + for optional library $ sudo apt-get install libreadline-dev libgsm1-dev libtheora-dev libsoup2.4-dev libsqlite3-dev libupnp4-dev diff --git a/README.macos b/README.macos index 87817ac54..1713b7968 100644 --- a/README.macos +++ b/README.macos @@ -7,9 +7,11 @@ You need: - Macports: http://www.macports.org/ Download and install macports using its user friendly installer. -- In order to enable generation of bundle for multiple macos version it is recommended to edit /opt/local/etc/macports/macports.conf to add the - following line: - macosx_deployment_target 10.6 +- In order to enable generation of bundle for multiple macos version and 32 bit processors, it is recommended to: + 1) edit /opt/local/etc/macports/macports.conf to add the following line: + macosx_deployment_target 10.6 + 2) edit /opt/local/etc/macports/variants.conf to add the following line: + +universal - Install build time dependencies $ sudo port install automake autoconf libtool intltool @@ -34,7 +36,16 @@ You need: The softwares below need to be compiled manually. To ensure compatibility with multiple mac os version it is recommended to do: $ export MACOSX_DEPLOYMENT_TARGET=10.6 + $ export CFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" + $ export OBJCFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" + $ export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" + $ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" +- Install polarssl (encryption library used by belle-sip) + $ git clone git://git.linphone.org/polarssl.git -b linphone + $ cd polarssl + $ ./autogen.sh && ./configure --prefix=/opt/local && make + $ sudo make install - Install belle-sip (sip stack) $ git clone git://git.linphone.org/belle-sip.git diff --git a/build/android/Android.mk b/build/android/Android.mk index 235056c54..e9c9fa1f6 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -85,6 +85,10 @@ LOCAL_CFLAGS += -DHAVE_X264 endif endif +ifeq ($(BUILD_CONTACT_HEADER),1) +LOCAL_CFLAGS += -DSAL_OP_CALL_FORCE_CONTACT_IN_RINGING +endif + ifeq ($(USE_JAVAH),1) LOCAL_CFLAGS += -DUSE_JAVAH endif diff --git a/coreapi/address.c b/coreapi/address.c index bb50fe30a..ec37255c1 100644 --- a/coreapi/address.c +++ b/coreapi/address.c @@ -112,11 +112,21 @@ void linphone_address_set_domain(LinphoneAddress *uri, const char *host){ * Sets the port number. **/ void linphone_address_set_port(LinphoneAddress *uri, int port){ -#ifdef USE_BELLESIP sal_address_set_port(uri,port); -#else - sal_address_set_port_int(uri,port); -#endif +} + +/** + * Set a transport. +**/ +void linphone_address_set_transport(LinphoneAddress *uri, LinphoneTransportType tp){ + sal_address_set_transport(uri,(SalTransport)tp); +} + +/** + * Get the transport. +**/ +LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri){ + return (LinphoneTransportType)sal_address_get_transport(uri); } /** @@ -142,6 +152,13 @@ char *linphone_address_as_string_uri_only(const LinphoneAddress *u){ return sal_address_as_string_uri_only(u); } +/** + * Returns true if address refers to a secure location (sips) +**/ +bool_t linphone_address_is_secure(const LinphoneAddress *uri){ + return sal_address_is_secure(uri); +} + static bool_t strings_equals(const char *s1, const char *s2){ if (s1==NULL && s2==NULL) return TRUE; if (s1!=NULL && s2!=NULL && strcmp(s1,s2)==0) return TRUE; diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c index 20da41fb2..91c2d91c8 100644 --- a/coreapi/bellesip_sal/sal_address_impl.c +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -43,6 +43,14 @@ const char *sal_address_get_scheme(const SalAddress *addr){ } else return NULL; } + +bool_t sal_address_is_secure(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + if (uri) return belle_sip_uri_is_secure(uri); + return FALSE; +} + const char *sal_address_get_display_name(const SalAddress* addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); return belle_sip_header_address_get_displayname(header_addr); @@ -52,17 +60,17 @@ const char *sal_address_get_display_name_unquoted(const SalAddress *addr){ return sal_address_get_display_name(addr); } #define SAL_ADDRESS_GET(addr,param) \ -belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);\ +{belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);\ belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);\ if (uri) {\ return belle_sip_uri_get_##param(uri);\ } else\ - return NULL; + return NULL;} -#define SAL_ADDRESS_SET(addr,param,value) \ +#define SAL_ADDRESS_SET(addr,param,value) {\ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);\ belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);\ -belle_sip_uri_set_##param(uri,value); +belle_sip_uri_set_##param(uri,value);} const char *sal_address_get_username(const SalAddress *addr){ SAL_ADDRESS_GET(addr,user) @@ -121,13 +129,19 @@ void sal_address_clean(SalAddress *addr){ } char *sal_address_as_string(const SalAddress *addr){ - return belle_sip_object_to_string(BELLE_SIP_OBJECT(addr)); + char tmp[1024]={0}; + size_t off=0; + belle_sip_object_marshal((belle_sip_object_t*)addr,tmp,sizeof(tmp),&off); + return ms_strdup(tmp); } char *sal_address_as_string_uri_only(const SalAddress *addr){ belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); - return belle_sip_object_to_string(BELLE_SIP_OBJECT(uri)); + char tmp[1024]={0}; + size_t off=0; + belle_sip_object_marshal((belle_sip_object_t*)uri,tmp,sizeof(tmp),&off); + return ms_strdup(tmp); } void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ @@ -137,7 +151,9 @@ void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ } void sal_address_set_transport(SalAddress* addr,SalTransport transport){ - SAL_ADDRESS_SET(addr,transport_param,sal_transport_to_string(transport)); + if (!sal_address_is_secure(addr)){ + SAL_ADDRESS_SET(addr,transport_param,sal_transport_to_string(transport)); + } } void sal_address_set_transport_name(SalAddress* addr,const char *transport){ diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index b3a7cfc78..abff14e99 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -22,6 +22,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef HAVE_CONFIG_H #include "config.h" #endif + +typedef struct belle_sip_certificates_chain_t _SalCertificatesChain; +typedef struct belle_sip_signing_key_t _SalSigningKey; + /* rfc3323 4.2 Expressing Privacy Preferences @@ -367,14 +371,16 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans } -static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { - SalAuthInfo* auth_info = sal_auth_info_create(auth_event); + +static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) { + SalAuthInfo* auth_info = sal_auth_info_create(event); ((Sal*)sal)->callbacks.auth_requested(sal,auth_info); - belle_sip_auth_event_set_passwd(auth_event,(const char*)auth_info->password); - belle_sip_auth_event_set_ha1(auth_event,(const char*)auth_info->ha1); - belle_sip_auth_event_set_userid(auth_event,(const char*)auth_info->userid); + belle_sip_auth_event_set_passwd(event,(const char*)auth_info->password); + belle_sip_auth_event_set_ha1(event,(const char*)auth_info->ha1); + belle_sip_auth_event_set_userid(event,(const char*)auth_info->userid); + belle_sip_auth_event_set_signing_key(event,(belle_sip_signing_key_t *)auth_info->key); + belle_sip_auth_event_set_client_certificates_chain(event,(belle_sip_certificates_chain_t* )auth_info->certificates); sal_auth_info_delete(auth_info); - return; } Sal * sal_init(){ @@ -477,11 +483,24 @@ void sal_uninit(Sal* sal){ belle_sip_object_unref(sal->prov); belle_sip_object_unref(sal->stack); belle_sip_object_unref(sal->listener); + if (sal->uuid) ms_free(sal->uuid); if (sal->root_ca) ms_free(sal->root_ca); ms_free(sal); - return ; }; +int sal_transport_available(Sal *sal, SalTransport t){ + switch(t){ + case SalTransportUDP: + case SalTransportTCP: + return TRUE; + case SalTransportTLS: + return belle_sip_stack_tls_available(sal->stack); + case SalTransportDTLS: + return FALSE; + } + return FALSE; +} + int sal_add_listen_port(Sal *ctx, SalAddress* addr){ int result; belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack @@ -699,9 +718,21 @@ SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(event)); auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event)); auth_info->domain = ms_strdup(belle_sip_auth_event_get_domain(event)); + auth_info->mode = (SalAuthMode)belle_sip_auth_event_get_mode(event); return auth_info; } +SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info) { return auth_info->mode; } +SalSigningKey *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info) { return auth_info->key; } +SalCertificatesChain *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info) { return auth_info->certificates; } +void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode) { auth_info->mode = mode; } +void sal_certificates_chain_delete(SalCertificatesChain *chain) { + belle_sip_object_unref((belle_sip_object_t *)chain); +} +void sal_signing_key_delete(SalSigningKey *key) { + belle_sip_object_unref((belle_sip_object_t *)key); +} + const char* sal_op_type_to_string(const SalOpType type) { switch(type) { case SalOpRegister: return "SalOpRegister"; @@ -839,14 +870,43 @@ void sal_enable_test_features(Sal*ctx, bool_t enabled){ ctx->enable_test_features=enabled; } -unsigned long sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data){ - return belle_sip_stack_resolve_a(sal->stack,name,port,family,(belle_sip_resolver_callback_t)cb,data); +SalResolverContext * sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data){ + return (SalResolverContext*)belle_sip_stack_resolve_a(sal->stack,name,port,family,(belle_sip_resolver_callback_t)cb,data); } -void sal_resolve_cancel(Sal *sal, unsigned long id){ - belle_sip_stack_resolve_cancel(sal->stack,id); +/* +void sal_resolve_cancel(Sal *sal, SalResolverContext* ctx){ + belle_sip_stack_resolve_cancel(sal->stack,ctx); } +*/ void sal_enable_unconditional_answer(Sal *sal,int value) { belle_sip_provider_enable_unconditional_answer(sal->prov,value); } + +/** Parse a file containing either a certificate chain order in PEM format or a single DER cert + * @param auth_info structure where to store the result of parsing + * @param path path to certificate chain file + * @param format either PEM or DER + */ +void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, SalCertificateRawFormat format) { + auth_info->certificates = (SalCertificatesChain*) belle_sip_certificates_chain_parse_file(path, (belle_sip_certificate_raw_format_t)format); // + if (auth_info->certificates) belle_sip_object_ref((belle_sip_object_t *) auth_info->certificates); +} + +/** + * Parse a file containing either a private or public rsa key + * @param auth_info structure where to store the result of parsing + * @param passwd password (optionnal) + */ +void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd) { + auth_info->key = (SalSigningKey *) belle_sip_signing_key_parse_file(path, passwd); + if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key); +} + +unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ + return belle_sip_random_bytes(ret,size); +} + + + diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 8a7037491..b434a1c38 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -362,7 +362,6 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } dialog_state=belle_sip_dialog_get_state(op->dialog); switch(dialog_state) { - case BELLE_SIP_DIALOG_NULL: { if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) { @@ -461,7 +460,13 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t }else{ SalBody salbody; if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) { - op->base.root->callbacks.info_received(op,&salbody); + if (sal_body_has_type(&salbody,"application","dtmf-relay")){ + char tmp[10]; + if (sal_lines_get_value(salbody.data, "Signal",tmp, sizeof(tmp))){ + op->base.root->callbacks.dtmf_received(op,tmp[0]); + } + }else + op->base.root->callbacks.info_received(op,&salbody); } else { op->base.root->callbacks.info_received(op,NULL); } @@ -485,10 +490,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t unsupported_method(server_transaction,req); } break; - default: { + default: ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); - } - /* no break */ + break; } if (server_transaction) belle_sip_object_unref(server_transaction); @@ -603,10 +607,17 @@ 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_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); - belle_sip_header_contact_t* contact_header; + belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("Require","100rel"))); belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("RSeq","1"))); + } + +#ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING + if (tags && strstr(tags,"100rel")!=0) +#endif + { + belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); + belle_sip_header_contact_t* contact_header; if (contact && (contact_header=belle_sip_header_contact_create(contact))) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header)); } @@ -693,7 +704,7 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ } int sal_call_send_dtmf(SalOp *h, char dtmf){ - if (h->dialog){ + if (h->dialog && (belle_sip_dialog_get_state(h->dialog) == BELLE_SIP_DIALOG_CONFIRMED || belle_sip_dialog_get_state(h->dialog) == BELLE_SIP_DIALOG_EARLY)){ belle_sip_request_t *req=belle_sip_dialog_create_queued_request(h->dialog,"INFO"); if (req){ int bodylen; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 02cb90a1f..4c6a1091a 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -220,13 +220,13 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req belle_sip_uri_t* outbound_proxy=NULL; belle_sip_header_contact_t* contact; int result =-1; + belle_sip_uri_t *next_hop_uri=NULL; _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) { /*don't put route header if dialog is in confirmed state*/ const MSList *elem=sal_op_get_route_addresses(op); - belle_sip_uri_t *next_hop_uri; const char *transport; const char *method=belle_sip_request_get_method(request); @@ -234,24 +234,25 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data); next_hop_uri=outbound_proxy; }else{ - next_hop_uri=belle_sip_request_get_uri(request); + next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request)); } transport=belle_sip_uri_get_transport_param(next_hop_uri); if (transport==NULL){ /*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use * the first available transport*/ - if (belle_sip_provider_get_listening_point(prov,"UDP")==0){ - if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ - transport="tcp"; - }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL){ - transport="tls"; + if (!belle_sip_uri_is_secure(next_hop_uri)){ + if (belle_sip_provider_get_listening_point(prov,"UDP")==0){ + if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ + transport="tcp"; + }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){ + transport="tls"; + } + } + if (transport){ + belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); + belle_sip_uri_set_transport_param(next_hop_uri,transport); } } - if (transport){ - belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); - belle_sip_uri_set_transport_param(next_hop_uri,transport); - } - /* not really usefull belle_sip_uri_fix(next_hop_uri);*/ } if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ @@ -279,7 +280,7 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req /*hmm just in case we already have authentication param in cache*/ belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL); } - result = belle_sip_client_transaction_send_request_to(client_transaction,outbound_proxy/*might be null*/); + result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/); /*update call id if not set yet for this OP*/ if (result == 0 && !op->base.call_id) { diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 23f9663fa..4c931cc33 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -25,29 +25,28 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mediastream.h" #include "lpconfig.h" +// stat +#ifndef WIN32 +#include +#include +#include +#endif + static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED; if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_CHANGED; - return sal_media_description_equals(oldmd, newmd); + if (call->localdesc_changed) ms_message("Local description has changed: %i", call->localdesc_changed); + return call->localdesc_changed | sal_media_description_equals(oldmd, newmd); } void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { - SalStreamDescription *old_audiodesc = NULL; - SalStreamDescription *old_videodesc = NULL; SalStreamDescription *new_audiodesc = NULL; SalStreamDescription *new_videodesc = NULL; char *rtp_addr, *rtcp_addr; int i; - for (i = 0; i < old_md->n_active_streams; i++) { - if (old_md->streams[i].type == SalAudio) { - old_audiodesc = &old_md->streams[i]; - } else if (old_md->streams[i].type == SalVideo) { - old_videodesc = &old_md->streams[i]; - } - } for (i = 0; i < new_md->n_active_streams; i++) { if (new_md->streams[i].type == SalAudio) { new_audiodesc = &new_md->streams[i]; @@ -68,22 +67,9 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); rtp_session_set_remote_addr_full(call->videostream->ms.session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); } +#else + (void)new_videodesc; #endif - - /* Copy address and port values from new_md to old_md since we will keep old_md as resultdesc */ - strcpy(old_md->addr, new_md->addr); - if (old_audiodesc && new_audiodesc) { - strcpy(old_audiodesc->rtp_addr, new_audiodesc->rtp_addr); - strcpy(old_audiodesc->rtcp_addr, new_audiodesc->rtcp_addr); - old_audiodesc->rtp_port = new_audiodesc->rtp_port; - old_audiodesc->rtcp_port = new_audiodesc->rtcp_port; - } - if (old_videodesc && new_videodesc) { - strcpy(old_videodesc->rtp_addr, new_videodesc->rtp_addr); - strcpy(old_videodesc->rtcp_addr, new_videodesc->rtcp_addr); - old_videodesc->rtp_port = new_videodesc->rtp_port; - old_videodesc->rtcp_port = new_videodesc->rtcp_port; - } } void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ @@ -105,9 +91,6 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia ms_message("Media descriptions are different, need to restart the streams."); } else { if (md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) { - /*as nothing has changed, keep the oldmd */ - call->resultdesc=oldmd; - sal_media_description_unref(new_md); if (call->all_muted){ ms_message("Early media finished, unmuting inputs..."); /*we were in early media, now we want to enable real media */ @@ -120,7 +103,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia #endif } ms_message("No need to restart streams, SDP is unchanged."); - return; + goto end; }else { if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) { ms_message("Network parameters have changed, update them."); @@ -130,17 +113,13 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia ms_message("Crypto parameters have changed, update them."); linphone_call_update_crypto_parameters(call, oldmd, new_md); } - call->resultdesc = oldmd; - sal_media_description_unref(new_md); - return; + goto end; } } } linphone_call_stop_media_streams (call); linphone_call_init_media_streams (call); } - if (oldmd) - sal_media_description_unref(oldmd); if (new_md) { bool_t all_muted=FALSE; @@ -162,6 +141,10 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){ linphone_core_play_named_tone(lc,LinphoneToneCallOnHold); } + end: + if (oldmd) + sal_media_description_unref(oldmd); + } #if 0 static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){ @@ -901,6 +884,46 @@ static void ping_reply(SalOp *op){ } } +static const char *get_client_cert_path(LinphoneCore *lc) { + static char cldir[200] = {0}; + #ifdef HAVE_GETENV + if (!cldir[0]) { + static char default_path[200] = {0}; + snprintf(default_path, sizeof(default_path), "%s%s", getenv("HOME"), "/linphone_certs"); + snprintf(cldir, sizeof(cldir), "%s", lp_config_get_string(lc->config,"sip","client_certificates_dir", default_path)); + } + #endif + return cldir; +} +static bool_t fill_auth_info_with_client_certificate(LinphoneCore *lc, SalAuthInfo* sai) { + char chain_file[200]; + char key_file[200]; + const char *path = get_client_cert_path(lc); + + snprintf(chain_file, sizeof(chain_file), "%s%s", path, "/chain.pem"); + + snprintf(key_file, sizeof(key_file), "%s%s", path, "/key.pem"); + +#ifndef WIN32 + { + // optinal check for files + struct stat st; + if (stat(key_file,&st)) { + ms_warning("No client certificate key found in %s", key_file); + return FALSE; + } + if (stat(chain_file,&st)) { + ms_warning("No client certificate chain found in %s", chain_file); + return FALSE; + } + } +#endif + + sal_certificates_chain_parse_file(sai, chain_file, SAL_CERTIFICATE_RAW_FORMAT_PEM ); + sal_signing_key_parse_file(sai, key_file, ""); + return sai->certificates && sai->key; +} + static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username,sai->domain); if (ai) { @@ -916,18 +939,25 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { } static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) { LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); - if (fill_auth_info(lc,sai)) { - return TRUE; - } else { - if (lc->vtable.auth_info_requested) { - lc->vtable.auth_info_requested(lc,sai->realm,sai->username,sai->domain); - if (fill_auth_info(lc,sai)) { - return TRUE; + if (sai->mode == SalAuthModeHttpDigest) { + if (fill_auth_info(lc,sai)) { + return TRUE; + } else { + if (lc->vtable.auth_info_requested) { + lc->vtable.auth_info_requested(lc,sai->realm,sai->username,sai->domain); + if (fill_auth_info(lc,sai)) { + return TRUE; + } } + return FALSE; } + } else if (sai->mode == SalAuthModeTls) { + return fill_auth_info_with_client_certificate(lc,sai); + } else { return FALSE; } } + static void notify_refer(SalOp *op, SalReferStatus status){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); diff --git a/coreapi/chat.c b/coreapi/chat.c index d220b0119..c2e6a9cf5 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -95,6 +95,7 @@ void linphone_chat_room_destroy(LinphoneChatRoom *cr){ lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr); linphone_address_destroy(cr->peer_url); ms_free(cr->peer); + ms_free(cr); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 7c24bbbd4..a952865ab 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -43,24 +43,34 @@ static MSWebCam *get_nowebcam_device(){ } #endif -static bool_t generate_b64_crypto_key(int key_length, char* key_out) { +static bool_t generate_b64_crypto_key(int key_length, char* key_out, size_t key_out_size) { int b64_size; - uint8_t* tmp = (uint8_t*) malloc(key_length); - if (ortp_crypto_get_random(tmp, key_length)!=0) { + uint8_t* tmp = (uint8_t*) ms_malloc0(key_length); + if (sal_get_random_bytes(tmp, key_length)==NULL) { ms_error("Failed to generate random key"); - free(tmp); + ms_free(tmp); return FALSE; } b64_size = b64_encode((const char*)tmp, key_length, NULL, 0); + if (b64_size == 0) { + ms_error("Failed to get b64 result size"); + ms_free(tmp); + return FALSE; + } + if (b64_size>=key_out_size){ + ms_error("Insufficient room for writing base64 SRTP key"); + ms_free(tmp); + return FALSE; + } + b64_size=b64_encode((const char*)tmp, key_length, key_out, key_out_size); if (b64_size == 0) { ms_error("Failed to b64 encode key"); - free(tmp); + ms_free(tmp); return FALSE; } key_out[b64_size] = '\0'; - b64_encode((const char*)tmp, key_length, key_out, 40); - free(tmp); + ms_free(tmp); return TRUE; } @@ -293,17 +303,18 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * if (md->streams[i].proto == SalProtoRtpSavp) { if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ int j; + ms_message("Keeping same crypto keys."); for(j=0;jstreams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo)); } }else{ md->streams[i].crypto[0].tag = 1; md->streams[i].crypto[0].algo = AES_128_SHA1_80; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key)) + if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key, SAL_SRTP_KEY_SIZE)) md->streams[i].crypto[0].algo = 0; md->streams[i].crypto[1].tag = 2; md->streams[i].crypto[1].algo = AES_128_SHA1_32; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key)) + if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key, SAL_SRTP_KEY_SIZE)) md->streams[i].crypto[1].algo = 0; md->streams[i].crypto[2].algo = 0; } @@ -322,7 +333,10 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * #endif //BUILD_UPNP linphone_address_destroy(addr); call->localdesc=md; - if (old_md) sal_media_description_unref(old_md); + if (old_md){ + call->localdesc_changed=sal_media_description_equals(md,old_md); + sal_media_description_unref(old_md); + } } static int find_port_offset(LinphoneCore *lc, SalStreamType type){ @@ -762,6 +776,7 @@ 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 @@ -1537,6 +1552,9 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m for(elem=desc->payloads;elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; int number; + /* make a copy of the payload type, so that we left the ones from the SalStreamDescription unchanged. + If the SalStreamDescription is freed, this will have no impact on the running streams*/ + pt=payload_type_clone(pt); if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) { if (desc->type==SalAudio){ @@ -1925,7 +1943,6 @@ void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { SalStreamDescription *old_stream; SalStreamDescription *new_stream; - int i; old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio); new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio); @@ -1940,11 +1957,6 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); call->audiostream_encrypted = FALSE; } - for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { - old_stream->crypto[i].tag = new_stream->crypto[i].tag; - old_stream->crypto[i].algo = new_stream->crypto[i].algo; - strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1); - } } } @@ -1962,11 +1974,6 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); call->videostream_encrypted = FALSE; } - for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { - old_stream->crypto[i].tag = new_stream->crypto[i].tag; - old_stream->crypto[i].algo = new_stream->crypto[i].algo; - strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1); - } } } #endif @@ -2031,6 +2038,7 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) { } audio_stream_stop(call->audiostream); call->audiostream=NULL; + call->current_params.audio_codec = NULL; } } @@ -2044,6 +2052,7 @@ void linphone_call_stop_video_stream(LinphoneCall *call) { linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream); video_stream_stop(call->videostream); call->videostream=NULL; + call->current_params.video_codec = NULL; } #endif } @@ -2056,12 +2065,10 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ ms_event_queue_skip(call->core->msevq); } if (call->audio_profile){ - rtp_profile_clear_all(call->audio_profile); rtp_profile_destroy(call->audio_profile); call->audio_profile=NULL; } if (call->video_profile){ - rtp_profile_clear_all(call->video_profile); rtp_profile_destroy(call->video_profile); call->video_profile=NULL; } @@ -2550,7 +2557,7 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0. * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0. * - * cx and cy are updated in return in case their coordinates were to excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video. + * cx and cy are updated in return in case their coordinates were too excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video. **/ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) { VideoStream* vstream = call->videostream; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index df4be1090..9bafb93da 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -942,6 +942,7 @@ static void build_video_devices_table(LinphoneCore *lc){ static void video_config_read(LinphoneCore *lc){ #ifdef VIDEO_ENABLED int capture, display, self_view; + int automatic_video=1; #endif const char *str; #ifdef VIDEO_ENABLED @@ -958,11 +959,14 @@ static void video_config_read(LinphoneCore *lc){ lp_config_get_string(lc->config,"video","size","cif")); #ifdef VIDEO_ENABLED +#if defined(ANDROID) || defined(__ios) + automatic_video=0; +#endif capture=lp_config_get_int(lc->config,"video","capture",1); display=lp_config_get_int(lc->config,"video","display",1); self_view=lp_config_get_int(lc->config,"video","self_view",1); - vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",1); - vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",1); + vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",automatic_video); + vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",automatic_video); linphone_core_enable_video_capture(lc, capture); linphone_core_enable_video_display(lc, display); linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0)); @@ -1888,6 +1892,13 @@ static int apply_transports(LinphoneCore *lc){ return 0; } +/** + * Returns TRUE if given transport type is supported by the library, FALSE otherwise. +**/ +bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp){ + return sal_transport_available(lc->sal,(SalTransport)tp); +} + /** * Sets the ports to be used for each of transport (UDP or TCP) * @@ -2275,8 +2286,8 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) enum_lookup_res_free(enumres); return uri; } - /* check if we have a "sip:" */ - if (strstr(url,"sip:")==NULL){ + /* check if we have a "sip:" or a "sips:" */ + if ( (strstr(url,"sip:")==NULL) && (strstr(url,"sips:")==NULL) ){ /* this doesn't look like a true sip uri */ if (strchr(url,'@')!=NULL){ /* seems like sip: is missing !*/ @@ -2401,11 +2412,7 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA if (transport){ SalAddress *route=sal_address_new(NULL); sal_address_set_domain(route,sal_address_get_domain((SalAddress*)dest)); -#ifdef USE_BELLESIP sal_address_set_port(route,sal_address_get_port((SalAddress*)dest)); -#else - sal_address_set_port_int(route,sal_address_get_port_int((SalAddress*)dest)); -#endif sal_address_set_transport_name(route,transport); ret=ms_list_append(ret,route); } @@ -2852,6 +2859,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (md){ if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ sal_call_decline(call->op,SalReasonMedia,NULL); + linphone_call_stop_media_streams(call); linphone_core_del_call(lc,call); linphone_call_unref(call); return; @@ -4896,8 +4904,10 @@ unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ /* unsets the video id for all calls (indeed it may be kept by filters or videostream object itself by paused calls)*/ static void unset_video_window_id(LinphoneCore *lc, bool_t preview, unsigned long id){ +#ifdef VIDEO_ENABLED LinphoneCall *call; MSList *elem; +#endif if (id!=0 && id!=-1) { ms_error("Invalid use of unset_video_window_id()"); @@ -5495,7 +5505,7 @@ static void sound_config_uninit(LinphoneCore *lc) if (config->local_ring) ms_free(config->local_ring); if (config->remote_ring) ms_free(config->remote_ring); - ms_snd_card_manager_destroy(); + } static void video_config_uninit(LinphoneCore *lc) @@ -5644,11 +5654,13 @@ static void linphone_core_uninit(LinphoneCore *lc) if(lc->rec_file!=NULL){ ms_free(lc->rec_file); } - + if(lc->presence_model){ + linphone_presence_model_unref(lc->presence_model); + } linphone_core_free_payload_types(lc); linphone_core_message_storage_close(lc); - ortp_exit(); + ms_exit(); linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 9ba12e8e8..317f01875 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -89,6 +89,19 @@ typedef struct _LCSipTransports{ } LCSipTransports; +/** + * Enum describing transport type for LinphoneAddress. +**/ +enum _LinphoneTransportType{ + LinphoneTransportUdp, + LinphoneTransportTcp, + LinphoneTransportTls, + LinphoneTransportDtls +}; +/*this enum MUST be kept in sync with the SalTransport from sal.h*/ + +typedef enum _LinphoneTransportType LinphoneTransportType; + /** * Object that represents a SIP address. * @@ -191,6 +204,9 @@ LINPHONE_PUBLIC void linphone_address_set_domain(LinphoneAddress *uri, const cha LINPHONE_PUBLIC void linphone_address_set_port(LinphoneAddress *uri, int port); /*remove tags, params etc... so that it is displayable to the user*/ LINPHONE_PUBLIC void linphone_address_clean(LinphoneAddress *uri); +LINPHONE_PUBLIC bool_t linphone_address_is_secure(const LinphoneAddress *uri); +LINPHONE_PUBLIC LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri); +LINPHONE_PUBLIC void linphone_address_set_transport(LinphoneAddress *uri,LinphoneTransportType type); LINPHONE_PUBLIC char *linphone_address_as_string(const LinphoneAddress *u); LINPHONE_PUBLIC char *linphone_address_as_string_uri_only(const LinphoneAddress *u); LINPHONE_PUBLIC bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2); @@ -1526,6 +1542,8 @@ LINPHONE_PUBLIC int linphone_core_get_sip_port(LinphoneCore *lc); LINPHONE_PUBLIC int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports *transports); LINPHONE_PUBLIC int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transports); + +LINPHONE_PUBLIC bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp); /** * * Give access to the UDP sip socket. Can be useful to configure this socket as persistent I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index a0e212c26..fa583f144 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -3102,7 +3102,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, jstring jdata){ + jstring jevname, jint expires, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ LinphoneCore *lc=(LinphoneCore*)coreptr; LinphoneAddress *addr=(LinphoneAddress*)addrptr; LinphoneContent content={0}; @@ -3114,14 +3114,16 @@ 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.data=(void*)env->GetStringUTFChars(jdata,NULL); - content.size=strlen((char*)content.data); + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL; + content.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); } ev=linphone_core_subscribe(lc,addr,evname,expires,content.type ? &content : NULL); if (jtype){ env->ReleaseStringUTFChars(jtype,content.type); env->ReleaseStringUTFChars(jsubtype,content.subtype); - env->ReleaseStringUTFChars(jdata,(char*)content.data); + if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding); + env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT); } env->ReleaseStringUTFChars(jevname,evname); if (ev){ @@ -3136,7 +3138,7 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_subscribe(JNIE * Signature: (JJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; */ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_publish(JNIEnv *env, jobject jobj, jlong coreptr, jlong addrptr, jstring jevname, jint expires, - jstring jtype, jstring jsubtype, jstring jdata){ + jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ LinphoneCore *lc=(LinphoneCore*)coreptr; LinphoneAddress *addr=(LinphoneAddress*)addrptr; LinphoneContent content={0}; @@ -3148,14 +3150,16 @@ 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.data=(void*)env->GetStringUTFChars(jdata,NULL); - content.size=strlen((char*)content.data); + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL; + content.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); } ev=linphone_core_publish(lc,addr,evname,expires,content.type ? &content : NULL); if (jtype){ env->ReleaseStringUTFChars(jtype,content.type); env->ReleaseStringUTFChars(jsubtype,content.subtype); - env->ReleaseStringUTFChars(jdata,(char*)content.data); + if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding); + env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT); } env->ReleaseStringUTFChars(jevname,evname); if (ev){ @@ -3295,15 +3299,22 @@ extern "C" jintArray Java_org_linphone_core_LpConfigImpl_getIntRange(JNIEnv *env static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *content){ jclass contentClass; jmethodID ctor; - jstring jtype, jsubtype, jdata; + jstring jtype, jsubtype, jencoding; + jbyteArray jdata=NULL; contentClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneContentImpl")); - ctor = env->GetMethodID(contentClass,"", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + ctor = env->GetMethodID(contentClass,"", "(Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;)V"); jtype=env->NewStringUTF(content->type); jsubtype=env->NewStringUTF(content->subtype); - jdata=content->data ? env->NewStringUTF((const char*)content->data) : NULL; - jobject jobj=env->NewObject(contentClass,ctor,jtype, jsubtype, jdata); + jencoding=content->encoding ? env->NewStringUTF(content->encoding) : NULL; + + if (content->data){ + jdata=env->NewByteArray(content->size); + env->SetByteArrayRegion(jdata,0,content->size,(jbyte*)content->data); + } + + jobject jobj=env->NewObject(contentClass,ctor,jtype, jsubtype, jdata,jencoding); env->DeleteGlobalRef(contentClass); return jobj; } @@ -3327,7 +3338,7 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getCont * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_setContent(JNIEnv *env, jobject jobj, jlong infoptr, jstring jtype, jstring jsubtype, jstring jdata){ - LinphoneContent content; + LinphoneContent content={0}; content.type=(char*)env->GetStringUTFChars(jtype,NULL); content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); @@ -3428,7 +3439,7 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_denySubscription * Method: notify * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I */ -JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_notify(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jstring jdata){ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_notify(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ LinphoneContent content={0}; LinphoneEvent *ev=(LinphoneEvent*)evptr; jint err; @@ -3436,8 +3447,9 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_notify(JNIEnv *e if (jtype){ content.type=(char*)env->GetStringUTFChars(jtype,NULL); content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); - content.data=(void*)env->GetStringUTFChars(jdata,NULL); - content.size=strlen((char*)content.data); + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL; + content.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); } err=linphone_event_notify(ev,content.type ? &content : NULL); @@ -3445,7 +3457,8 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_notify(JNIEnv *e if (jtype){ env->ReleaseStringUTFChars(jtype,content.type); env->ReleaseStringUTFChars(jsubtype,content.subtype); - env->ReleaseStringUTFChars(jdata,(char*)content.data); + if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding); + env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT); } return err; } @@ -3455,7 +3468,7 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_notify(JNIEnv *e * Method: updateSubscribe * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I */ -JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updateSubscribe(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jstring jdata){ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updateSubscribe(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ LinphoneContent content={0}; LinphoneEvent *ev=(LinphoneEvent*)evptr; jint err; @@ -3463,8 +3476,9 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updateSubscribe( if (jtype){ content.type=(char*)env->GetStringUTFChars(jtype,NULL); content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); - content.data=(void*)env->GetStringUTFChars(jdata,NULL); - content.size=strlen((char*)content.data); + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL; + content.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); } err=linphone_event_update_subscribe(ev,content.type ? &content : NULL); @@ -3472,7 +3486,8 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updateSubscribe( if (jtype){ env->ReleaseStringUTFChars(jtype,content.type); env->ReleaseStringUTFChars(jsubtype,content.subtype); - env->ReleaseStringUTFChars(jdata,(char*)content.data); + if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding); + env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT); } return err; } @@ -3482,7 +3497,7 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updateSubscribe( * Method: updatePublish * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I */ -JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updatePublish(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jstring jdata){ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updatePublish(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ LinphoneContent content={0}; LinphoneEvent *ev=(LinphoneEvent*)evptr; jint err; @@ -3490,8 +3505,9 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updatePublish(JN if (jtype){ content.type=(char*)env->GetStringUTFChars(jtype,NULL); content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); - content.data=(void*)env->GetStringUTFChars(jdata,NULL); - content.size=strlen((char*)content.data); + content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL; + content.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); } err=linphone_event_update_publish(ev,content.type ? &content : NULL); @@ -3499,7 +3515,8 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updatePublish(JN if (jtype){ env->ReleaseStringUTFChars(jtype,content.type); env->ReleaseStringUTFChars(jsubtype,content.subtype); - env->ReleaseStringUTFChars(jdata,(char*)content.data); + if (jencoding) env->ReleaseStringUTFChars(jencoding,content.encoding); + env->ReleaseByteArrayElements(jdata,(jbyte*)content.data,JNI_ABORT); } return err; } diff --git a/coreapi/misc.c b/coreapi/misc.c index 7d9b70b3f..c96fde835 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -633,7 +633,7 @@ static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addr ms_warning("Stun server resolution failed."); } lc->net_conf.stun_addrinfo=addrinfo; - lc->net_conf.stun_res_id=0; + lc->net_conf.stun_res=NULL; } void linphone_core_resolve_stun_server(LinphoneCore *lc){ @@ -642,7 +642,7 @@ void linphone_core_resolve_stun_server(LinphoneCore *lc){ char host[NI_MAXHOST]; int port=3478; linphone_parse_host_port(server,host,sizeof(host),&port); - lc->net_conf.stun_res_id=sal_resolve_a(lc->sal,host,port,AF_UNSPEC,(SalResolverCallback)stun_server_resolved,lc); + lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_UNSPEC,(SalResolverCallback)stun_server_resolved,lc); } } @@ -663,7 +663,7 @@ const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc){ int wait_ms=0; int wait_limit=1000; linphone_core_resolve_stun_server(lc); - while (!lc->net_conf.stun_addrinfo && lc->net_conf.stun_res_id!=0 && wait_msnet_conf.stun_addrinfo && lc->net_conf.stun_res!=NULL && wait_mssal); ms_usleep(50000); wait_ms+=50; diff --git a/coreapi/private.h b/coreapi/private.h index 20397cefc..e4ddd59c0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -199,6 +199,8 @@ 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; + bool_t refer_pending; bool_t media_pending; bool_t audio_muted; @@ -498,7 +500,7 @@ typedef struct net_config char *nat_address_ip; /* ip translated from nat_address */ char *stun_server; struct addrinfo *stun_addrinfo; - unsigned long stun_res_id; + SalResolverContext * stun_res; int download_bw; int upload_bw; int mtu; diff --git a/coreapi/sal.c b/coreapi/sal.c index 49e70b3c6..25fa8dcd8 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -26,6 +26,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "config.h" #endif #include "sal/sal.h" + +#include + const char* sal_transport_to_string(SalTransport transport) { switch (transport) { case SalTransportUDP:return "udp"; @@ -483,6 +486,9 @@ void sal_auth_info_delete(SalAuthInfo* auth_info) { if (auth_info->realm) ms_free(auth_info->realm); if (auth_info->domain) ms_free(auth_info->domain); if (auth_info->password) ms_free(auth_info->password); + if (auth_info->ha1) ms_free(auth_info->ha1); + if (auth_info->certificates) sal_certificates_chain_delete(auth_info->certificates); + if (auth_info->key) sal_signing_key_delete(auth_info->key); ms_free(auth_info); } @@ -569,3 +575,55 @@ const char* sal_privacy_to_string(SalPrivacy privacy) { default: return NULL; } } + +static void remove_trailing_spaces(char *line){ + int i; + for(i=strlen(line)-1;i>=0;--i){ + if (isspace(line[i])) line[i]='\0'; + else break; + } +} + +static int line_get_value(const char *input, const char *key, char *value, size_t value_size, int *read){ + const char *end=strchr(input,'\n'); + char line[256]={0}; + char key_candidate[256]; + char *equal; + size_t len; + if (!end) len=strlen(input); + else len=end +1 -input; + *read=len; + strncpy(line,input,MIN(len,sizeof(line))); + equal=strchr(line,'='); + if (!equal) return FALSE; + *equal='\0'; + if (sscanf(line,"%s",key_candidate)!=1) return FALSE; + if (strcasecmp(key,key_candidate)==0){ + equal++; + remove_trailing_spaces(equal); + strncpy(value,equal,value_size-1); + value[value_size-1]='\0'; + return TRUE; + } + return FALSE; +} + +int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size){ + int read=0; + + do{ + if (line_get_value(data,key,value,value_size,&read)) + return TRUE; + data+=read; + }while(read!=0); + return FALSE; +} + +int sal_body_has_type(const SalBody *body, const char *type, const char *subtype){ + return body->type && body->subtype + && strcmp(body->type,type)==0 + && strcmp(body->subtype,subtype)==0; +} + + + diff --git a/gtk/keypad.ui b/gtk/keypad.ui index 6b5376762..5dfcfc487 100644 --- a/gtk/keypad.ui +++ b/gtk/keypad.ui @@ -8,8 +8,11 @@ True False + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK 0.5 none + + True diff --git a/gtk/main.c b/gtk/main.c index 6aabf98c5..d8a8a2ede 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -64,6 +64,7 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl) static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg); static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token); static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate); +static void linphone_gtk_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data); static gboolean linphone_gtk_auto_answer(LinphoneCall *call); void linphone_gtk_status_icon_set_blinking(gboolean val); @@ -251,6 +252,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.buddy_info_updated=linphone_gtk_buddy_info_updated; vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; vtable.transfer_state_changed=linphone_gtk_transfer_state_changed; + vtable.dtmf_received=linphone_gtk_dtmf_received; the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); @@ -797,6 +799,9 @@ gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_ date, id); } + if (!dir) { + ms_message ("No directory for music, using [%s] instead",dir=getenv("HOME")); + } return g_build_filename(dir,filename,NULL); } @@ -1046,6 +1051,10 @@ static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm auth_timeout_new(w); } +static void linphone_gtk_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){ + ms_message("Dtmf %c received.",dtmf); +} + static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){ GtkWidget *w=linphone_gtk_get_main_window(); GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar"); @@ -1712,6 +1721,40 @@ void linphone_gtk_init_dtmf_table(GtkWidget *mw){ g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*"); } +static gboolean key_allowed(guint32 code){ + static const char *allowed="1234567890#*ABCD"; + return code!=0 && strchr(allowed,(char)code)!=NULL; +} + +static GtkButton *get_button_from_key(GtkWidget *w, GdkEvent *event){ + guint keyval=event->key.keyval; + guint32 code=gdk_keyval_to_unicode(keyval); + code=g_unichar_toupper(code); + if (key_allowed(code)){ + char widgetname[16]; + w=gtk_widget_get_toplevel(w); + snprintf(widgetname,sizeof(widgetname),"dtmf_%c",code); + return GTK_BUTTON(linphone_gtk_get_widget(w,widgetname)); + } + return NULL; +} + +void linphone_gtk_keypad_key_pressed(GtkWidget *w, GdkEvent *event, gpointer userdata){ + GtkButton *button=get_button_from_key(w,event); + if (button) { + linphone_gtk_dtmf_pressed(button); + /*g_signal_emit_by_name(button, "button-press-event");*/ + } +} + +void linphone_gtk_keypad_key_released(GtkWidget *w, GdkEvent *event, gpointer userdata){ + GtkButton *button=get_button_from_key(w,event); + if (button) { + linphone_gtk_dtmf_released(button); + /*g_signal_emit_by_name(button, "button-release-event");*/ + } +} + void linphone_gtk_create_keypad(GtkWidget *button){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad"); diff --git a/gtk/main.ui b/gtk/main.ui index dde462ec3..ae1335c5d 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1548,6 +1548,7 @@ True + True True False none diff --git a/gtk/parameters.ui b/gtk/parameters.ui index 6624ec01c..4cb435eb2 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -48,6 +48,12 @@ 1 9.9999999995529656 + + 65535 + 5060 + 1 + 10 + 65535 2 @@ -324,23 +330,10 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 7 + 8 2 - - True - False - model8 - - - - 0 - - - - - - + True True @@ -350,6 +343,7 @@ True True adjustment7 + 1 @@ -363,8 +357,8 @@ Media encryption type - 3 - 5 + 4 + 6 @@ -376,24 +370,8 @@ 1 2 - 3 - 4 - - - - - gtk-edit - True - True - False - True - - - - 1 - 2 - 6 - 7 + 4 + 5 @@ -405,8 +383,8 @@ right - 2 - 3 + 3 + 4 @@ -418,36 +396,8 @@ right - 1 - 2 - - - - - True - False - DSCP fields - - - 5 - 6 - - - - - gtk-edit - True - True - True - False - True - - - - 1 - 2 - 5 - 6 + 2 + 3 @@ -513,8 +463,8 @@ 1 2 - 1 - 2 + 2 + 3 @@ -580,18 +530,8 @@ 1 2 - 2 - 3 - - - - - False - Tunnel - - - 6 - 7 + 3 + 4 @@ -607,10 +547,102 @@ 1 2 - 4 - 5 + 5 + 6 + + + False + Tunnel + + + 7 + 8 + + + + + gtk-edit + True + True + False + True + + + + 1 + 2 + 7 + 8 + + + + + True + False + DSCP fields + + + 6 + 7 + + + + + gtk-edit + True + True + True + False + True + + + + 1 + 2 + 6 + 7 + + + + + True + False + SIP/TCP port + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + adjustment8 + + + + 1 + 2 + 1 + 2 + + + + + True + False + SIP/UDP port + + diff --git a/gtk/propertybox.c b/gtk/propertybox.c index bcdb52812..c4dcd72ae 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -102,49 +102,6 @@ void linphone_gtk_update_my_contact(GtkWidget *w){ linphone_gtk_load_identities(); } -void linphone_gtk_update_my_port(GtkWidget *w){ - GtkWidget *pb=gtk_widget_get_toplevel(GTK_WIDGET(w)); - LCSipTransports tr; - LinphoneCore *lc=linphone_gtk_get_core(); - GtkComboBox *combo = GTK_COMBO_BOX(linphone_gtk_get_widget(pb, "proto_combo")); - - gint port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - if (port == 1) { // We use default port if not specified - if (strcmp(gtk_combo_box_get_active_text(combo), "SIP (UDP)") == 0) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), - 5060); - } - else if (strcmp(gtk_combo_box_get_active_text(combo), "SIP (TCP)") == 0) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), - 5060); - } - else if (strcmp(gtk_combo_box_get_active_text(combo), "SIP (TLS)") == 0) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), - 5061); - } - } - - linphone_core_get_sip_transports(lc,&tr); - gchar *selected = gtk_combo_box_get_active_text(combo); - if (strcmp(selected, "SIP (TCP)") == 0) { - tr.tcp_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - tr.udp_port = 0; - tr.tls_port = 0; - } - else if (strcmp(gtk_combo_box_get_active_text(GTK_COMBO_BOX(linphone_gtk_get_widget(pb, "proto_combo"))), "SIP (UDP)") == 0) { - tr.udp_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - tr.tcp_port = 0; - tr.tls_port = 0; - } - else if (strcmp(gtk_combo_box_get_active_text(GTK_COMBO_BOX(linphone_gtk_get_widget(pb, "proto_combo"))), "SIP (TLS)") == 0){ - tr.udp_port = 0; - tr.tcp_port = 0; - tr.tls_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - } - - linphone_core_set_sip_transports(lc,&tr); -} - void linphone_gtk_set_propety_entry(GtkWidget *w, gboolean stunServer, gboolean ip){ GtkWidget *stun_entry=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"stun_server"); GtkWidget *ip_entry=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"nat_address"); @@ -691,6 +648,77 @@ static void linphone_gtk_proxy_closed(GtkWidget *w){ } } +static void fill_transport_combo_box(GtkWidget *combo, LinphoneTransportType choice, gboolean is_sensitive){ + GtkTreeModel *model; + GtkTreeIter iter; + + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(combo),"combo-updating"))) return; + + if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){ + /*case where combo box is created with no model*/ + GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); + model=GTK_TREE_MODEL(gtk_list_store_new(1,G_TYPE_STRING)); + gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"markup",0,NULL); + } + if (!gtk_tree_model_get_iter_first(model,&iter)){ + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"UDP",-1); + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"TCP",-1); + if (linphone_core_sip_transport_supported(linphone_gtk_get_core(),LinphoneTransportTls)){ + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"TLS",-1); + } + } + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),(int)choice); + gtk_widget_set_sensitive(combo,is_sensitive); +} + +static void update_proxy_transport(GtkWidget *w){ + const char *addr=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy"))); + LinphoneAddress *laddr=linphone_address_new(addr); + if (laddr){ + GtkWidget *combo=linphone_gtk_get_widget(w,"transport"); + if (linphone_address_is_secure(laddr)){ + fill_transport_combo_box(combo,LinphoneTransportTls,FALSE); + }else{ + fill_transport_combo_box(combo,linphone_address_get_transport(laddr),TRUE); + } + linphone_address_destroy(laddr); + } +} + +void linphone_gtk_proxy_transport_changed(GtkWidget *combo){ + GtkWidget *w=gtk_widget_get_toplevel(combo); + int index=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); + GtkWidget *proxy=linphone_gtk_get_widget(w,"proxy"); + const char *addr=gtk_entry_get_text(GTK_ENTRY(proxy)); + LinphoneAddress *laddr; + LinphoneTransportType new_transport=(LinphoneTransportType)index; + + if (index==-1) return; + + g_object_set_data(G_OBJECT(w),"combo-updating",GINT_TO_POINTER(1)); + laddr=linphone_address_new(addr); + if (laddr){ + if (linphone_address_get_transport(laddr)!=new_transport){ + char *newaddr; + linphone_address_set_transport(laddr,new_transport); + newaddr=linphone_address_as_string(laddr); + gtk_entry_set_text(GTK_ENTRY(proxy),newaddr); + ms_free(newaddr); + } + linphone_address_destroy(laddr); + } + g_object_set_data(G_OBJECT(w),"combo-updating",GINT_TO_POINTER(0)); +} + +void linphone_gtk_proxy_address_changed(GtkEditable *editable){ + update_proxy_transport(gtk_widget_get_toplevel(GTK_WIDGET(editable))); +} + void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){ GtkWidget *w=linphone_gtk_create_window("sip_account"); const char *tmp; @@ -698,8 +726,7 @@ void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){ linphone_proxy_config_edit(cfg); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")), linphone_proxy_config_get_identity(cfg)); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")), - linphone_proxy_config_get_addr(cfg)); + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")),linphone_proxy_config_get_addr(cfg)); tmp=linphone_proxy_config_get_route(cfg); if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")),tmp); tmp=linphone_proxy_config_get_contact_parameters(cfg); @@ -723,17 +750,36 @@ void linphone_gtk_proxy_cancel(GtkButton *button){ } void linphone_gtk_proxy_ok(GtkButton *button){ + LinphoneCore *lc=linphone_gtk_get_core(); GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); + int index=gtk_combo_box_get_active(GTK_COMBO_BOX(linphone_gtk_get_widget(w,"transport"))); + LinphoneTransportType tport=(LinphoneTransportType)index; gboolean was_editing=TRUE; + if (!cfg){ was_editing=FALSE; cfg=linphone_proxy_config_new(); } linphone_proxy_config_set_identity(cfg, gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")))); - linphone_proxy_config_set_server_addr(cfg, - gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")))); + if (linphone_proxy_config_set_server_addr(cfg, + gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy"))))==0){ + if (index!=-1){ + /*make sure transport was added to proxy address*/ + LinphoneAddress *laddr=linphone_address_new(linphone_proxy_config_get_addr(cfg)); + if (laddr){ + if (linphone_address_get_transport(laddr)!=tport){ + char *tmp; + linphone_address_set_transport(laddr,tport); + tmp=linphone_address_as_string(laddr); + linphone_proxy_config_set_server_addr(cfg,tmp); + ms_free(tmp); + } + linphone_address_destroy(laddr); + } + } + } linphone_proxy_config_set_route(cfg, gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")))); linphone_proxy_config_set_contact_parameters(cfg, @@ -747,6 +793,17 @@ void linphone_gtk_proxy_ok(GtkButton *button){ linphone_proxy_config_enable_register(cfg, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")))); + + /* check if tls was asked but is not enabled in transport configuration*/ + if (tport==LinphoneTransportTls){ + LCSipTransports tports; + linphone_core_get_sip_transports(lc,&tports); + if (tports.tls_port==LC_SIP_TRANSPORT_DISABLED){ + tports.tls_port=LC_SIP_TRANSPORT_RANDOM; + } + linphone_core_set_sip_transports(lc,&tports); + } + if (was_editing){ if (linphone_proxy_config_done(cfg)==-1) return; @@ -901,14 +958,6 @@ void linphone_gtk_lang_changed(GtkComboBox *combo){ } } -void linphone_gtk_proto_changed(GtkComboBox *combo){ - GtkWidget *pb=gtk_widget_get_toplevel(GTK_WIDGET(combo)); - - GtkWidget *proto_port = linphone_gtk_get_widget(pb, "proto_port"); - // When we change the network protocol, we call update_my_port to move the port number from the old protocol to the new one - linphone_gtk_update_my_port(proto_port); -} - static void linphone_gtk_ui_level_adapt(GtkWidget *top) { gboolean ui_advanced; const char *simple_ui = linphone_gtk_get_ui_config("simple_ui", "parameters.codec_tab parameters.transport_frame parameters.ports_frame"); @@ -1074,6 +1123,48 @@ void linphone_gtk_fill_video_renderers(GtkWidget *pb){ if (active!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); } +typedef struct { + guint timeout_id; + LCSipTransports tp; +}PortConfigCtx; + +static void port_config_free(PortConfigCtx *ctx){ + g_free(ctx); +} + +static void apply_transports(PortConfigCtx *ctx){ + GtkWidget *mw=linphone_gtk_get_main_window(); + LCSipTransports tp; + LinphoneCore *lc=linphone_gtk_get_core(); + linphone_core_get_sip_transports(lc,&tp); + tp.udp_port=ctx->tp.udp_port; + tp.tcp_port=ctx->tp.tcp_port; + linphone_core_set_sip_transports(lc,&tp); + g_object_set_data(G_OBJECT(mw),"port_config",NULL); +} + +static void transport_changed(GtkWidget *parameters){ + GtkWidget *mw=linphone_gtk_get_main_window(); + PortConfigCtx *cfg=(PortConfigCtx*)g_object_get_data(G_OBJECT(mw),"port_config"); + if (cfg==NULL){ + cfg=g_new0(PortConfigCtx,1); + g_object_set_data_full(G_OBJECT(mw),"port_config",cfg,(GDestroyNotify)port_config_free); + } + if (cfg->timeout_id!=0) + g_source_remove(cfg->timeout_id); + cfg->tp.udp_port=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(linphone_gtk_get_widget(parameters,"sip_udp_port"))); + cfg->tp.tcp_port=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(linphone_gtk_get_widget(parameters,"sip_tcp_port"))); + cfg->timeout_id=g_timeout_add_seconds(2,(GSourceFunc)apply_transports,cfg); +} + +void linphone_gtk_udp_port_value_changed(GtkSpinButton *button){ + transport_changed(gtk_widget_get_toplevel((GtkWidget*)button)); +} + +void linphone_gtk_tcp_port_value_changed(GtkSpinButton *button){ + transport_changed(gtk_widget_get_toplevel((GtkWidget*)button)); +} + void linphone_gtk_show_parameters(void){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); @@ -1101,21 +1192,11 @@ void linphone_gtk_show_parameters(void){ linphone_core_ipv6_enabled(lc)); linphone_core_get_sip_transports(lc,&tr); - if (tr.tcp_port > 0) { - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 1); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")), - tr.tcp_port); - } - else if (tr.tls_port > 0) { - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 2); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")), - tr.tls_port); - } - else { - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 0); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")), + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_udp_port")), tr.udp_port); - } + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_tcp_port")), + tr.tcp_port); + linphone_core_get_audio_port_range(lc, &min_port, &max_port); gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port); @@ -1214,10 +1295,6 @@ void linphone_gtk_show_parameters(void){ ui_advanced); linphone_gtk_ui_level_adapt(pb); - g_signal_connect(G_OBJECT(linphone_gtk_get_widget(pb,"proto_port")),"value-changed",(GCallback)linphone_gtk_update_my_port,NULL); - g_signal_connect(G_OBJECT(linphone_gtk_get_widget(pb,"proto_combo")),"changed",(GCallback)linphone_gtk_proto_changed,NULL); - - if (linphone_core_tunnel_available()){ gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_edit_button")), TRUE); gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_label")), TRUE); diff --git a/gtk/sip_account.ui b/gtk/sip_account.ui index 9c23c806d..d0a93d5dc 100644 --- a/gtk/sip_account.ui +++ b/gtk/sip_account.ui @@ -1,6 +1,7 @@ + 100000 3600 @@ -15,13 +16,13 @@ center-on-parent dialog - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 2 - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -91,7 +92,7 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 + 6 2 @@ -112,6 +113,8 @@ sip: False False + True + True 1 @@ -140,6 +143,9 @@ sip: False False + True + True + 1 @@ -148,19 +154,6 @@ 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Route (optional): - right - - - 2 - 3 - - True @@ -168,12 +161,14 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True 1 2 - 2 - 3 + 4 + 5 @@ -185,24 +180,26 @@ right - 3 - 4 + 2 + 3 True True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True adjustment1 1 2 - 3 - 4 + 2 + 3 @@ -210,12 +207,12 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Contact params: + Contact params (optional): right - 4 - 5 + 5 + 6 @@ -228,15 +225,53 @@ True False False + True + True 1 2 + 5 + 6 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Route (optional): + right + + 4 5 - + + + True + False + Transport + + + 3 + 4 + + + + + True + False + + + + 1 + 2 + 3 + 4 + + True diff --git a/include/sal/sal.h b/include/sal/sal.h index dd6a8f5db..6374e2a08 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -85,12 +85,9 @@ const char *sal_address_get_display_name(const SalAddress* addr); const char *sal_address_get_display_name_unquoted(const SalAddress *addr); const char *sal_address_get_username(const SalAddress *addr); const char *sal_address_get_domain(const SalAddress *addr); -#ifdef USE_BELLESIP int sal_address_get_port(const SalAddress *addr); -#else -const char * sal_address_get_port(const SalAddress *addr); -int sal_address_get_port_int(const SalAddress *addr); -#endif +bool_t sal_address_is_secure(const SalAddress *addr); + SalTransport sal_address_get_transport(const SalAddress* addr); const char* sal_address_get_transport_name(const SalAddress* addr); @@ -169,11 +166,13 @@ typedef struct SalIceRemoteCandidate { #define SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN 256 #define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256 +#define SAL_SRTP_KEY_SIZE 41 + typedef struct SalSrtpCryptoAlgo { unsigned int tag; enum ortp_srtp_crypto_suite_t algo; /* 41= 40 max(key_length for all algo) + '\0' */ - char master_key[41]; + char master_key[SAL_SRTP_KEY_SIZE]; } SalSrtpCryptoAlgo; #define SAL_CRYPTO_ALGO_MAX 4 @@ -331,6 +330,29 @@ typedef enum SalTextDeliveryStatus{ SalTextDeliveryFailed }SalTextDeliveryStatus; +/** + * auth event mode + * */ +typedef enum SalAuthMode { /*this enum must be same as belle_sip_auth_mode_t*/ + SalAuthModeHttpDigest, /** Digest authentication requested*/ + SalAuthModeTls /** Client certificate requested*/ +}SalAuthMode; + +struct _SalCertificatesChain; +typedef struct _SalCertificatesChain SalCertificatesChain; +struct _SalSigningKey; +typedef struct _SalSigningKey SalSigningKey; + +/** + * Format of certificate buffer + * */ +typedef enum SalCertificateRawFormat {/*this enum must be same as belle_sip_certificate_raw_format_t*/ + SAL_CERTIFICATE_RAW_FORMAT_PEM, /** PEM format*/ + SAL_CERTIFICATE_RAW_FORMAT_DER /** ASN.1 raw format*/ +}SalCertificateRawFormat; + + + typedef struct SalAuthInfo{ char *username; char *userid; @@ -338,6 +360,9 @@ typedef struct SalAuthInfo{ char *realm; char *domain; char *ha1; + SalAuthMode mode; + SalSigningKey *key; + SalCertificatesChain *certificates; }SalAuthInfo; typedef struct SalBody{ @@ -424,10 +449,34 @@ SalAuthInfo* sal_auth_info_new(); SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info); void sal_auth_info_delete(SalAuthInfo* auth_info); LINPHONE_PUBLIC int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]); +SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info); +SalSigningKey *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info); +SalCertificatesChain *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info); +void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode); + +/** Parse a file containing either a certificate chain order in PEM format or a single DER cert + * @param auth_info structure where to store the result of parsing + * @param path path to certificate chain file + * @param format either PEM or DER + */ +void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, SalCertificateRawFormat format); + +/** + * Parse a file containing either a private or public rsa key + * @param auth_info structure where to store the result of parsing + * @param passwd password (optionnal) + */ +void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd); + +void sal_certificates_chain_delete(SalCertificatesChain *chain); +void sal_signing_key_delete(SalSigningKey *key); + + void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs); int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure); int sal_unlisten_ports(Sal *ctx); +int sal_transport_available(Sal *ctx, SalTransport t); void sal_set_dscp(Sal *ctx, int dscp); int sal_reset_transports(Sal *ctx); ortp_socket_t sal_get_socket(Sal *ctx); @@ -594,8 +643,10 @@ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t ipl typedef void (*SalResolverCallback)(void *data, const char *name, struct addrinfo *ai_list); -unsigned long sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data); -void sal_resolve_cancel(Sal *sal, unsigned long id); +typedef struct SalResolverContext SalResolverContext; + +SalResolverContext * sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data); +//void sal_resolve_cancel(Sal *sal, SalResolverContext *ctx); SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value); const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name); @@ -636,4 +687,10 @@ 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_dns_user_hosts_file(Sal *sal, const char *hosts_file); LINPHONE_PUBLIC const char *sal_get_dns_user_hosts_file(const Sal *sal); +unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size); + +int sal_body_has_type(const SalBody *body, const char *type, const char *subtype); +/*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/ +int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size); + #endif diff --git a/java/common/org/linphone/core/LinphoneContent.java b/java/common/org/linphone/core/LinphoneContent.java index b3811006f..10c6e3dc9 100644 --- a/java/common/org/linphone/core/LinphoneContent.java +++ b/java/common/org/linphone/core/LinphoneContent.java @@ -17,11 +17,19 @@ public interface LinphoneContent { * @return the subtype */ String getSubtype(); + /** + * Get the encoding applied to the data, can be null if no encoding. + **/ + String getEncoding(); /** * Get the data as a string. * @return the data */ String getDataAsString(); + /** + * Get the data as a byte array. + **/ + byte [] getData(); /** * Get the data size. * @return the data size. @@ -38,9 +46,17 @@ public interface LinphoneContent { * @param subtype the subtype */ void setSubtype(String subtype); + /** + * Set the encoding applied to the data, can be null if no encoding. + **/ + void setEncoding(String encoding); /** * Set the data, supplied as String. * @param data the data */ void setStringData(String data); + /** + * Set the data, as a byte buffer. + **/ + void setData(byte data[]); } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index dfbeb883b..95cfdeaf0 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -108,10 +108,15 @@ abstract public class LinphoneCoreFactory { abstract public LinphoneFriend createLinphoneFriend(); /** - * Create a LinphoneContent object + * Create a LinphoneContent object from string data. */ abstract public LinphoneContent createLinphoneContent(String type, String subType, String data); + /** + * Create a LinphoneContent object from byte array. + */ + abstract public LinphoneContent createLinphoneContent(String type, String subType,byte [] data, String encoding); + /** * Create a PresenceActivity object. */ diff --git a/java/impl/org/linphone/core/LinphoneContentImpl.java b/java/impl/org/linphone/core/LinphoneContentImpl.java index f74711042..b12e6580f 100644 --- a/java/impl/org/linphone/core/LinphoneContentImpl.java +++ b/java/impl/org/linphone/core/LinphoneContentImpl.java @@ -1,11 +1,14 @@ package org.linphone.core; public class LinphoneContentImpl implements LinphoneContent { - private String mType, mSubtype, mData; - public LinphoneContentImpl(String type, String subtype, String data){ + private String mType, mSubtype, mEncoding; + private byte[] mData; + + public LinphoneContentImpl(String type, String subtype, byte data[], String encoding ){ mType=type; mSubtype=subtype; mData=data; + mEncoding=encoding; } @Override @@ -20,12 +23,12 @@ public class LinphoneContentImpl implements LinphoneContent { @Override public String getDataAsString() { - return mData; + return new String(mData); } @Override public int getSize() { - return mData.length(); + return mData.length; } @Override @@ -40,7 +43,27 @@ public class LinphoneContentImpl implements LinphoneContent { @Override public void setStringData(String data) { + mData=data.getBytes(); + } + + @Override + public void setData(byte data[]){ mData=data; } + @Override + public String getEncoding() { + return mEncoding; + } + + @Override + public byte[] getData() { + return mData; + } + + @Override + public void setEncoding(String encoding) { + mEncoding=encoding; + } + } diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index d2f635d4d..e526b47b5 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -151,10 +151,16 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { return new LinphoneAuthInfoImpl(username, userid, passwd, ha1, realm, domain); } + @Override + public LinphoneContent createLinphoneContent(String type, String subType, + byte [] data, String encoding) { + return new LinphoneContentImpl(type,subType,data,encoding); + } + @Override public LinphoneContent createLinphoneContent(String type, String subType, String data) { - return new LinphoneContentImpl(type,subType,data); + return new LinphoneContentImpl(type,subType,data.getBytes(),null); } @Override diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index f5740ff41..420547e57 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -1028,19 +1028,21 @@ class LinphoneCoreImpl implements LinphoneCore { return new LinphoneInfoMessageImpl(createInfoMessage(nativePtr)); } - private native Object subscribe(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, String data); + private native Object subscribe(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, byte data [], String encoding); @Override public LinphoneEvent subscribe(LinphoneAddress resource, String eventname, int expires, LinphoneContent content) { return (LinphoneEvent)subscribe(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, - content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getDataAsString() : null); + content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getData() : null, + content!=null ? content.getEncoding() : null); } - private native Object publish(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, String data); + private native Object publish(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, byte data [], String encoding); @Override public LinphoneEvent publish(LinphoneAddress resource, String eventname, int expires, LinphoneContent content) { return (LinphoneEvent)publish(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, - content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getDataAsString() : null); + content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getData() : null, + content!=null ? content.getEncoding() : null); } public void setChatDatabasePath(String path) { diff --git a/java/impl/org/linphone/core/LinphoneEventImpl.java b/java/impl/org/linphone/core/LinphoneEventImpl.java index ab201af99..9890f7cdf 100644 --- a/java/impl/org/linphone/core/LinphoneEventImpl.java +++ b/java/impl/org/linphone/core/LinphoneEventImpl.java @@ -26,22 +26,22 @@ public class LinphoneEventImpl implements LinphoneEvent { denySubscription(mNativePtr,reason.mValue); } - private native int notify(long nativeptr, String type, String subtype, String data); + private native int notify(long nativeptr, String type, String subtype, byte data[], String encoding); @Override public void notify(LinphoneContent content) { - notify(mNativePtr,content.getType(),content.getSubtype(),content.getDataAsString()); + notify(mNativePtr,content.getType(),content.getSubtype(),content.getData(),content.getEncoding()); } - private native int updateSubscribe(long nativePtr, String type, String subtype, String data); + private native int updateSubscribe(long nativePtr, String type, String subtype, byte data[], String encoding); @Override public void updateSubscribe(LinphoneContent content) { - updateSubscribe(mNativePtr,content.getType(), content.getSubtype(),content.getDataAsString()); + updateSubscribe(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); } - private native int updatePublish(long nativePtr, String type, String subtype, String data); + private native int updatePublish(long nativePtr, String type, String subtype, byte data[], String encoding); @Override public void updatePublish(LinphoneContent content) { - updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getDataAsString()); + updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); } private native int terminate(long nativePtr); diff --git a/mediastreamer2 b/mediastreamer2 index 785a5d8f7..8deb23a1b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 785a5d8f76c336a51f8a21997e9dcaee669d4ec4 +Subproject commit 8deb23a1b03e343b753d2e896347453ada72e4df diff --git a/tester/call_tester.c b/tester/call_tester.c index 267d2050e..8e5c952f7 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -382,12 +382,16 @@ static void call_failed_because_of_codecs(void) { static void call_with_dns_time_out(void) { LinphoneCoreManager* marie = linphone_core_manager_new2( "empty_rc", FALSE); LCSipTransports transport = {9773,0,0,0}; + int i; + linphone_core_set_sip_transports(marie->lc,&transport); linphone_core_iterate(marie->lc); sal_set_dns_timeout(marie->lc->sal,0); linphone_core_invite(marie->lc,"sip:toto@toto.com"); - linphone_core_iterate(marie->lc); - linphone_core_iterate(marie->lc); + for(i=0;i<10;i++){ + ms_usleep(200000); + linphone_core_iterate(marie->lc); + } CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); @@ -1023,9 +1027,10 @@ static void srtp_ice_call(void) { CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); check_rtcp(marie,pauline); -#endif /*wait for ice to found the direct path*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); +#endif + /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); diff --git a/tester/certificates/altname/cacert.pem b/tester/certificates/altname/cafile.pem similarity index 100% rename from tester/certificates/altname/cacert.pem rename to tester/certificates/altname/cafile.pem diff --git a/tester/certificates/cn/cacert.pem b/tester/certificates/cn/cafile.pem similarity index 100% rename from tester/certificates/cn/cacert.pem rename to tester/certificates/cn/cafile.pem diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 3c0fe9635..465e4c925 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -107,7 +107,7 @@ static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); sal_enable_test_features(lc->sal,TRUE); - snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cacert.pem", path); + snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cafile.pem", path); linphone_core_set_root_ca(lc,rootcapath); sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); @@ -178,7 +178,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; - int proxy_count=check_for_proxies?(rc_file?1:0):0; + int proxy_count; int retry=0; mgr->v_table.registration_state_changed=registration_state_changed; @@ -197,8 +197,12 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f linphone_core_set_user_data(mgr->lc,mgr); reset_counters(&mgr->stat); /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ + if (check_for_proxies && rc_file) /**/ + proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)); + else + proxy_count=0; - while (mgr->stat.number_of_LinphoneRegistrationOkstat.number_of_LinphoneRegistrationOk2?(proxy_count-2)*10:0))) { linphone_core_iterate(mgr->lc); ms_usleep(100000); } diff --git a/tester/message_tester.c b/tester/message_tester.c index 5b111a302..c3001c226 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -220,7 +220,7 @@ static void info_message_with_args(bool_t with_content) { info=linphone_core_create_info_message(marie->lc); linphone_info_message_add_header(info,"Weather","still bad"); if (with_content) { - LinphoneContent ct; + LinphoneContent ct={0}; ct.type="application"; ct.subtype="somexml"; ct.data=(void*)info_content; diff --git a/tester/register_tester.c b/tester/register_tester.c index adf3197a8..9531c1447 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -537,7 +537,7 @@ static void tls_certificate_failure(){ linphone_core_set_root_ca(mgr->lc,NULL); /*no root ca*/ linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationFailed,2)); - snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cacert.pem", liblinphone_tester_file_prefix); /*goot root ca*/ + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cafile.pem", liblinphone_tester_file_prefix); /*goot root ca*/ linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); @@ -575,7 +575,7 @@ static void tls_alt_name_register(){ mgr=linphone_core_manager_new2("pauline_alt_rc",FALSE); lc=mgr->lc; - snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cacert.pem", liblinphone_tester_file_prefix); + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cafile.pem", liblinphone_tester_file_prefix); linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); @@ -590,7 +590,7 @@ static void tls_wildcard_register(){ mgr=linphone_core_manager_new2("pauline_wild_rc",FALSE); lc=mgr->lc; - snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cacert.pem", liblinphone_tester_file_prefix); + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cafile.pem", liblinphone_tester_file_prefix); linphone_core_set_root_ca(mgr->lc,rootcapath); linphone_core_refresh_registers(mgr->lc); CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,2)); diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 06949f82c..7a5bac9c9 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -68,11 +68,35 @@ static void core_sip_transport_test(void) { linphone_core_destroy(lc); } +static void linphone_interpret_url_test() +{ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + const char* sips_address = "sips:margaux@sip.linphone.org"; + LinphoneAddress* address; + + memset ( &v_table,0,sizeof ( v_table ) ); + lc = linphone_core_new ( &v_table,NULL,NULL,NULL ); + CU_ASSERT_PTR_NOT_NULL_FATAL ( lc ); + + address = linphone_core_interpret_url(lc, sips_address); + + CU_ASSERT_PTR_NOT_NULL_FATAL(address); + CU_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_scheme(address), "sips"); + CU_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_username(address), "margaux"); + CU_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_domain(address), "sip.linphone.org"); + + linphone_address_destroy(address); + + linphone_core_destroy ( lc ); +} + test_t setup_tests[] = { { "Linphone Address", linphone_address_test }, { "Linphone core init/uninit", core_init_test }, - { "Linphone random transport port",core_sip_transport_test} + { "Linphone random transport port",core_sip_transport_test}, + { "Linphone interpret url", linphone_interpret_url_test } }; test_suite_t setup_test_suite = { diff --git a/tools/Makefile.am b/tools/Makefile.am index 6fa7fadb4..5ef2535ad 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,7 +12,7 @@ COMMON_CFLAGS=\ $(LIBXML2_CFLAGS) #-fpermissive to workaround a g++ bug on macos 32bit SDK. -AM_CXXFLAGS=$(LIBXML2_CFLAGS) $(STRICT_OPTIONS) -fpermissive +AM_CXXFLAGS=$(LIBXML2_CFLAGS) -fpermissive $(STRICT_OPTIONS) EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc