Merge branch 'dev_sal'

This commit is contained in:
Simon Morlat 2010-03-25 21:20:14 +01:00
commit 97e377cf5d
34 changed files with 5318 additions and 2284 deletions

9
NEWS
View file

@ -1,9 +1,18 @@
linphone-3.3.0 -- ?????????
* liblinphone is ported to iphoneOS and Google Android
* Internal refactoring of liblinphone (code factorisation, encapsulation
of signaling)
* enhancements made to presence support (SIP/SIMPLE)
linphone-3.2.2 -- ?????????
* improve bitrate usage of speex codec
* allow speex to run with vbr (variable bit rate) mode
* add speex/32000 (ultra wide band speex codec)
* answer empty SIP INFO requests
* reverse order of call logs
* optimize video display
* manual or automatic network connectivity management (so that REGISTERs
are only sent when network is up or refreshed when it comes back)
linphone-3.2.1 -- October 5, 2009
* improve graphics and behaviour of mute button

View file

@ -13,7 +13,7 @@ INCLUDES = \
bin_PROGRAMS = linphonec sipomatic linphonecsh
bin_PROGRAMS = linphonec linphonecsh
if BUILD_WIN32
bin_PROGRAMS += linphoned

View file

@ -1337,7 +1337,7 @@ linphonec_proxy_use(LinphoneCore *lc, int index)
static void
linphonec_friend_display(LinphoneFriend *fr)
{
LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_uri(fr));
LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_address(fr));
char *str;
linphonec_out("name: %s\n", linphone_address_get_display_name(uri));
@ -1362,7 +1362,7 @@ linphonec_friend_list(LinphoneCore *lc, char *pat)
{
if ( pat ) {
const char *name = linphone_address_get_display_name(
linphone_friend_get_uri((LinphoneFriend*)friend->data));
linphone_friend_get_address((LinphoneFriend*)friend->data));
if (name && ! strstr(name, pat) ) continue;
}
linphonec_out("****** Friend %i *******\n",n);
@ -1384,7 +1384,7 @@ linphonec_friend_call(LinphoneCore *lc, unsigned int num)
if ( n == num )
{
int ret;
addr = linphone_address_as_string(linphone_friend_get_uri((LinphoneFriend*)friend->data));
addr = linphone_address_as_string(linphone_friend_get_address((LinphoneFriend*)friend->data));
ret=lpc_cmd_call(lc, addr);
ms_free(addr);
return ret;
@ -1458,17 +1458,16 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){
return 1;
}
if (passwd[0]!='\0'){
osip_from_t *from;
LinphoneAddress *from;
LinphoneAuthInfo *info;
osip_from_init(&from);
if (osip_from_parse(from,identity)==0){
if ((from=linphone_address_new(identity))!=NULL){
char realm[128];
snprintf(realm,sizeof(realm)-1,"\"%s\"",from->url->host);
info=linphone_auth_info_new(from->url->username,NULL,passwd,NULL,NULL);
snprintf(realm,sizeof(realm)-1,"\"%s\"",linphone_address_get_domain(from));
info=linphone_auth_info_new(linphone_address_get_username(from),NULL,passwd,NULL,NULL);
linphone_core_add_auth_info(lc,info);
linphone_address_destroy(from);
linphone_auth_info_destroy(info);
}
osip_from_free(from);
}
elem=linphone_core_get_proxy_config_list(lc);
if (elem) {
@ -1674,7 +1673,8 @@ static void linphonec_codec_list(LinphoneCore *lc){
MSList *node;
for(node=config->audio_codecs;node!=NULL;node=ms_list_next(node)){
pt=(PayloadType*)(node->data);
linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, payload_type_enabled(pt) ? "enabled" : "disabled");
linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate,
linphone_core_payload_type_enabled(lc,pt) ? "enabled" : "disabled");
index++;
}
}

View file

@ -119,8 +119,7 @@ static void linphonec_display_something (LinphoneCore * lc, const char *somethin
static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
static void linphonec_display_warning (LinphoneCore * lc, const char *something);
static void stub () {}
static void linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid,
const char *from, const char *status, const char *img);
static void linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid);
static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
LinphoneFriend *lf, const char *url);
static void linphonec_bye_received(LinphoneCore *lc, const char *from);
@ -283,10 +282,11 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern
* Linphone core callback
*/
static void
linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid,
const char *from, const char *status, const char *img)
linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid)
{
printf("Friend %s is %s\n", from, status);
char *tmp=linphone_address_as_string(linphone_friend_get_address(fid));
printf("Friend %s is %s\n", tmp, linphone_online_status_to_string(linphone_friend_get_status(fid)));
ms_free(tmp);
// todo: update Friend list state (unimplemented)
}

View file

@ -17,18 +17,22 @@ lib_LTLIBRARIES=liblinphone.la
liblinphone_la_SOURCES=\
linphonecore.c linphonecore.h private.h\
exevents.c exevents.h \
offeranswer.c offeranswer.h\
sal.c sal.h \
sal_eXosip2.c sal_eXosip2.h\
sal_eXosip2_sdp.c \
sal_eXosip2_presence.c \
callbacks.c \
misc.c \
address.c \
enum.c enum.h \
sdphandler.c sdphandler.h \
presence.c \
proxy.c \
friend.c \
authentication.c \
lpconfig.c lpconfig.h \
chat.c \
general_state.c \
general_state.c \
sipsetup.c sipsetup.h \
siplogin.c

View file

@ -20,7 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "linphonecore.h"
#include "lpconfig.h"
#include "private.h"
#include <eXosip2/eXosip.h>
/**
* @addtogroup linphone_address
@ -31,123 +30,87 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Constructs a LinphoneAddress object by parsing the user supplied address,
* given as a string.
**/
LinphoneAddress * linphone_address_new(const char *uri){
osip_from_t *from;
osip_from_init(&from);
if (osip_from_parse(from,uri)!=0){
osip_from_free(from);
ms_error("Cannot create LinphoneAddress, bad uri [%s]",uri);
return NULL;
}
return from;
LinphoneAddress * linphone_address_new(const char *addr){
SalAddress *saddr=sal_address_new(addr);
if (saddr==NULL) ms_error("Cannot create LinphoneAddress, bad uri [%s]",addr);
return saddr;
}
/**
* Clones a LinphoneAddress object.
**/
LinphoneAddress * linphone_address_clone(const LinphoneAddress *uri){
osip_from_t *ret=NULL;
osip_from_clone(uri,&ret);
return ret;
LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr){
return sal_address_clone(addr);
}
#define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL )
/**
* Returns the address scheme, normally "sip".
**/
const char *linphone_address_get_scheme(const LinphoneAddress *u){
return null_if_empty(u->url->scheme);
return sal_address_get_scheme(u);
}
/**
* Returns the display name.
**/
const char *linphone_address_get_display_name(const LinphoneAddress* u){
return null_if_empty(u->displayname);
return sal_address_get_display_name(u);
}
/**
* Returns the username.
**/
const char *linphone_address_get_username(const LinphoneAddress *u){
return null_if_empty(u->url->username);
return sal_address_get_username(u);
}
/**
* Returns the domain name.
**/
const char *linphone_address_get_domain(const LinphoneAddress *u){
return null_if_empty(u->url->host);
return sal_address_get_domain(u);
}
/**
* Sets the display name.
**/
void linphone_address_set_display_name(LinphoneAddress *u, const char *display_name){
if (u->displayname!=NULL){
osip_free(u->displayname);
u->displayname=NULL;
}
if (display_name!=NULL)
u->displayname=osip_strdup(display_name);
sal_address_set_display_name(u,display_name);
}
/**
* Sets the username.
**/
void linphone_address_set_username(LinphoneAddress *uri, const char *username){
if (uri->url->username!=NULL){
osip_free(uri->url->username);
uri->url->username=NULL;
}
if (username)
uri->url->username=osip_strdup(username);
sal_address_set_username(uri,username);
}
/**
* Sets the domain.
**/
void linphone_address_set_domain(LinphoneAddress *uri, const char *host){
if (uri->url->host!=NULL){
osip_free(uri->url->host);
uri->url->host=NULL;
}
if (host)
uri->url->host=osip_strdup(host);
sal_address_set_domain(uri,host);
}
/**
* Sets the port number.
**/
void linphone_address_set_port(LinphoneAddress *uri, const char *port){
if (uri->url->port!=NULL){
osip_free(uri->url->port);
uri->url->port=NULL;
}
if (port)
uri->url->port=osip_strdup(port);
sal_address_set_port(uri,port);
}
/**
* Sets the port number.
**/
void linphone_address_set_port_int(LinphoneAddress *uri, int port){
char tmp[12];
if (port==5060){
/*this is the default, special case to leave the port field blank*/
linphone_address_set_port(uri,NULL);
return;
}
snprintf(tmp,sizeof(tmp),"%i",port);
linphone_address_set_port(uri,tmp);
sal_address_set_port_int(uri,port);
}
/**
* Removes address's tags and uri headers so that it is displayable to the user.
**/
void linphone_address_clean(LinphoneAddress *uri){
osip_generic_param_freelist(&uri->gen_params);
sal_address_clean(uri);
}
/**
@ -155,11 +118,7 @@ void linphone_address_clean(LinphoneAddress *uri){
* The returned char * must be freed by the application. Use ms_free().
**/
char *linphone_address_as_string(const LinphoneAddress *u){
char *tmp,*ret;
osip_from_to_str(u,&tmp);
ret=ms_strdup(tmp);
osip_free(tmp);
return ret;
return sal_address_as_string(u);
}
/**
@ -167,18 +126,14 @@ char *linphone_address_as_string(const LinphoneAddress *u){
* The returned char * must be freed by the application. Use ms_free().
**/
char *linphone_address_as_string_uri_only(const LinphoneAddress *u){
char *tmp=NULL,*ret;
osip_uri_to_str(u->url,&tmp);
ret=ms_strdup(tmp);
osip_free(tmp);
return ret;
return sal_address_as_string_uri_only(u);
}
/**
* Destroys a LinphoneAddress object.
**/
void linphone_address_destroy(LinphoneAddress *u){
osip_from_free(u);
sal_address_destroy(u);
}

View file

@ -24,12 +24,8 @@
#include "linphonecore.h"
#include "private.h"
#include <eXosip2/eXosip.h>
#include <osipparser2/osip_message.h>
#include "lpconfig.h"
extern LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid);
/**
* @addtogroup authentication
* @{
@ -51,7 +47,6 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri
if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1);
if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm);
obj->works=FALSE;
obj->first_time=TRUE;
return obj;
}
@ -63,10 +58,28 @@ static LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){
if (ai->ha1) obj->ha1=ms_strdup(ai->ha1);
if (ai->realm) obj->realm=ms_strdup(ai->realm);
obj->works=FALSE;
obj->first_time=TRUE;
obj->usecount=0;
return obj;
}
/**
* Returns username.
**/
const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i){
return i->username;
}
/**
* Returns password.
**/
const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i){
return i->passwd;
}
const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i){
return i->userid;
}
/**
* Sets the password.
**/
@ -224,21 +237,6 @@ const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const cha
return ret;
}
static void refresh_exosip_auth_info(LinphoneCore *lc){
MSList *elem;
eXosip_lock();
eXosip_clear_authentication_info();
for (elem=lc->auth_info;elem!=NULL;elem=ms_list_next(elem)){
LinphoneAuthInfo *info=(LinphoneAuthInfo*)elem->data;
char *userid;
if (info->userid==NULL || info->userid[0]=='\0') userid=info->username;
else userid=info->userid;
eXosip_add_authentication_info(info->username,userid,
info->passwd,info->ha1,info->realm);
}
eXosip_unlock();
}
/**
* Adds authentication information to the LinphoneCore.
*
@ -247,6 +245,7 @@ static void refresh_exosip_auth_info(LinphoneCore *lc){
void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
{
LinphoneAuthInfo *ai;
MSList *elem;
/* find if we are attempting to modify an existing auth info */
ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username);
@ -255,10 +254,23 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
linphone_auth_info_destroy(ai);
}
lc->auth_info=ms_list_append(lc->auth_info,linphone_auth_info_clone(info));
refresh_exosip_auth_info(lc);
/* if the user was prompted, re-allow automatic_action */
if (lc->automatic_action>0) lc->automatic_action--;
/* retry pending authentication operations */
for(elem=sal_get_pending_auths(lc->sal);elem!=NULL;elem=elem->next){
const char *username,*realm;
SalOp *op=(SalOp*)elem->data;
LinphoneAuthInfo *ai;
sal_op_get_auth_requested(op,&realm,&username);
ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
if (ai){
SalAuthInfo sai;
sai.username=ai->username;
sai.userid=ai->userid;
sai.realm=ai->realm;
sai.password=ai->passwd;
sal_op_authenticate(op,&sai);
ai->usecount++;
}
}
}
@ -267,7 +279,6 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
* from the auth_info_requested callback of LinphoneCoreVTable.
**/
void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *info){
if (lc->automatic_action>0) lc->automatic_action--;
}
/**
@ -286,7 +297,6 @@ void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *in
linphone_auth_info_write_config(lc->config,(LinphoneAuthInfo*)elem->data,i);
}
linphone_auth_info_write_config(lc->config,NULL,i);
refresh_exosip_auth_info(lc);
}
}
@ -303,9 +313,6 @@ const MSList *linphone_core_get_auth_info_list(const LinphoneCore *lc){
void linphone_core_clear_all_auth_info(LinphoneCore *lc){
MSList *elem;
int i;
eXosip_lock();
eXosip_clear_authentication_info();
eXosip_unlock();
for(i=0,elem=lc->auth_info;elem!=NULL;elem=ms_list_next(elem),i++){
LinphoneAuthInfo *info=(LinphoneAuthInfo*)elem->data;
linphone_auth_info_destroy(info);
@ -315,84 +322,6 @@ void linphone_core_clear_all_auth_info(LinphoneCore *lc){
lc->auth_info=NULL;
}
void linphone_authentication_ok(LinphoneCore *lc, eXosip_event_t *ev){
char *prx_realm=NULL,*www_realm=NULL;
osip_proxy_authorization_t *prx_auth;
osip_authorization_t *www_auth;
osip_message_t *msg=ev->request;
char *username;
LinphoneAuthInfo *as=NULL;
username=osip_uri_get_username(msg->from->url);
osip_message_get_proxy_authorization(msg,0,&prx_auth);
osip_message_get_authorization(msg,0,&www_auth);
if (prx_auth!=NULL)
prx_realm=osip_proxy_authorization_get_realm(prx_auth);
if (www_auth!=NULL)
www_realm=osip_authorization_get_realm(www_auth);
if (prx_realm==NULL && www_realm==NULL){
ms_message("No authentication info in the request, ignoring");
return;
}
/* see if we already have this auth information , not to ask it everytime to the user */
if (prx_realm!=NULL)
as=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,prx_realm,username);
if (www_realm!=NULL)
as=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,www_realm,username);
if (as){
ms_message("Authentication for user=%s realm=%s is working.",username,prx_realm ? prx_realm : www_realm);
as->works=TRUE;
}
}
void linphone_core_find_or_ask_for_auth_info(LinphoneCore *lc,const char *username,const char* realm, int tid)
{
LinphoneAuthInfo *as=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
if ( as==NULL || (as!=NULL && as->works==FALSE && as->first_time==FALSE)){
if (lc->vtable.auth_info_requested!=NULL){
lc->vtable.auth_info_requested(lc,realm,username);
lc->automatic_action++;/*suspends eXosip_automatic_action until the user supplies a password */
}
}
if (as) as->first_time=FALSE;
}
void linphone_process_authentication(LinphoneCore *lc, eXosip_event_t *ev)
{
char *prx_realm=NULL,*www_realm=NULL;
osip_proxy_authenticate_t *prx_auth;
osip_www_authenticate_t *www_auth;
osip_message_t *resp=ev->response;
char *username;
/*
if (strcmp(ev->request->sip_method,"REGISTER")==0) {
gstate_new_state(lc, GSTATE_REG_FAILED, "Authentication required");
}
*/
username=osip_uri_get_username(resp->from->url);
prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0);
www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0);
if (prx_auth!=NULL)
prx_realm=osip_proxy_authenticate_get_realm(prx_auth);
if (www_auth!=NULL)
www_realm=osip_www_authenticate_get_realm(www_auth);
if (prx_realm==NULL && www_realm==NULL){
ms_warning("No realm in the server response.");
return;
}
/* see if we already have this auth information , not to ask it everytime to the user */
if (prx_realm!=NULL)
linphone_core_find_or_ask_for_auth_info(lc,username,prx_realm,ev->tid);
if (www_realm!=NULL)
linphone_core_find_or_ask_for_auth_info(lc,username,www_realm,ev->tid);
}
/**
* @}
**/

457
coreapi/callbacks.c Normal file
View file

@ -0,0 +1,457 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sal.h"
#include "linphonecore.h"
#include "private.h"
#include "mediastreamer2/mediastream.h"
static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
if (lc->vtable.show)
lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Connected."));
call->state=LCStateAVRunning;
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_start_media_streams(lc,call);
}
static void call_received(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
char *barmesg;
LinphoneCall *call;
const char *from,*to;
char *tmp;
LinphoneAddress *from_parsed;
/* first check if we can answer successfully to this invite */
if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){
ms_message("Not present !! presence mode : %d\n",lc->presence_mode);
if (lc->presence_mode==LINPHONE_STATUS_BUSY)
sal_call_decline(h,SalReasonBusy,NULL);
else if (lc->presence_mode==LINPHONE_STATUS_AWAY
||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK
||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE
||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH
||lc->presence_mode==LINPHONE_STATUS_OFFLINE)
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB)
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED)
sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
else
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(h);
return;
}
if (lc->call!=NULL){/*busy*/
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(h);
return;
}
from=sal_op_get_from(h);
to=sal_op_get_to(h);
call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h);
lc->call=call;
sal_call_set_local_media_description(h,call->localdesc);
call->resultdesc=sal_call_get_final_media_description(h);
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
sal_call_decline(h,SalReasonMedia,NULL);
linphone_call_destroy(call);
lc->call=NULL;
return;
}
from_parsed=linphone_address_new(sal_op_get_from(h));
linphone_address_clean(from_parsed);
tmp=linphone_address_as_string(from_parsed);
linphone_address_destroy(from_parsed);
gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp);
barmesg=ortp_strdup_printf(_("%s is contacting you"),tmp);
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,barmesg);
/* play the ring */
if (lc->sound_conf.ring_sndcard!=NULL){
ms_message("Starting local ring...");
lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard);
}
linphone_call_set_state(call,LCStateRinging);
sal_call_notify_ringing(h);
linphone_core_init_media_streams(lc,lc->call);
if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
ms_free(barmesg);
ms_free(tmp);
}
static void call_ringing(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneCall *call=lc->call;
SalMediaDescription *md;
if (call==NULL) return;
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Remote ringing."));
md=sal_call_get_final_media_description(h);
if (md==NULL){
if (lc->ringstream!=NULL) return; /*already ringing !*/
if (lc->sound_conf.play_sndcard!=NULL){
ms_message("Remote ringing...");
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard);
}
}else{
/*accept early media */
if (lc->audiostream && lc->audiostream->ticker!=NULL){
/*streams already started */
ms_message("Early media already started.");
return;
}
sal_media_description_ref(md);
call->resultdesc=md;
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Early media."));
gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
ms_message("Doing early media...");
linphone_core_start_media_streams(lc,call);
call->media_pending=TRUE;
}
call->state=LCStateRinging;
}
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=lc->call;
if (call==NULL){
ms_warning("No call to accept.");
return ;
}
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_accepted: ignoring.");
return;
}
if (call->state==LCStateAVRunning){
return ; /*already accepted*/
}
if (lc->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc){
sal_media_description_ref(call->resultdesc);
call->media_pending=FALSE;
}
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
linphone_connect_incoming(lc,call);
}else{
/*send a bye*/
ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
linphone_core_terminate_call(lc,NULL);
}
}
static void call_ack(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=lc->call;
if (call==NULL){
ms_warning("No call to be ACK'd");
return ;
}
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_ack: ignoring.");
return;
}
if (call->media_pending){
if (lc->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
linphone_connect_incoming(lc,call);
}else{
/*send a bye*/
ms_error("Incompatible SDP response received in ACK, need to abort the call");
linphone_core_terminate_call(lc,NULL);
}
call->media_pending=FALSE;
}
}
static void call_updated(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
linphone_connect_incoming(lc,call);
}
}
static void call_terminated(SalOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_terminated: ignoring.");
return;
}
ms_message("Current call terminated...");
if (lc->ringstream!=NULL) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_stop_media_streams(lc,lc->call);
lc->vtable.show(lc);
lc->vtable.display_status(lc,_("Call terminated."));
gstate_new_state(lc, GSTATE_CALL_END, NULL);
if (lc->vtable.bye_recv!=NULL){
LinphoneAddress *addr=linphone_address_new(from);
char *tmp;
linphone_address_clean(addr);
tmp=linphone_address_as_string(addr);
lc->vtable.bye_recv(lc,tmp);
ms_free(tmp);
linphone_address_destroy(addr);
}
linphone_call_destroy(lc->call);
lc->call=NULL;
}
static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
char *msg486=_("User is busy.");
char *msg480=_("User is temporarily unavailable.");
/*char *retrymsg=_("%s. Retry after %i minute(s).");*/
char *msg600=_("User does not want to be disturbed.");
char *msg603=_("Call declined.");
LinphoneCall *call=lc->call;
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_failure: ignoring.");
return;
}
if (lc->vtable.show) lc->vtable.show(lc);
if (error==SalErrorNoResponse){
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("No response."));
}else if (error==SalErrorProtocol){
if (lc->vtable.display_status)
lc->vtable.display_status(lc, details ? details : _("Error."));
}else if (error==SalErrorFailure){
switch(sr){
case SalReasonDeclined:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg603);
break;
case SalReasonBusy:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg486);
break;
case SalReasonRedirect:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Redirected"));
break;
case SalReasonTemporarilyUnavailable:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg480);
break;
case SalReasonNotFound:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Not found"));
break;
case SalReasonDoNotDisturb:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg600);
break;
case SalReasonMedia:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("No common codecs"));
break;
default:
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Call failed."));
}
}
if (lc->ringstream!=NULL) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_stop_media_streams(lc,call);
if (call!=NULL) {
linphone_call_destroy(call);
gstate_new_state(lc, GSTATE_CALL_ERROR, NULL);
lc->call=NULL;
}
}
static void auth_requested(SalOp *h, const char *realm, const char *username){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
ms_message("auth_requested() for realm=%s, username=%s",realm,username);
if (ai && (ai->works || ai->usecount<3)){
SalAuthInfo sai;
sai.username=ai->username;
sai.userid=ai->userid;
sai.realm=ai->realm;
sai.password=ai->passwd;
ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username);
sal_op_authenticate(h,&sai);
ai->usecount++;
}else{
if (lc->vtable.auth_info_requested)
lc->vtable.auth_info_requested(lc,realm,username);
}
}
static void auth_success(SalOp *h, const char *realm, const char *username){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
if (ai){
ms_message("%s/%s authentication works.",realm,username);
ai->works=TRUE;
}
}
static void register_success(SalOp *op, bool_t registered){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
char *msg;
gstate_new_state(lc, GSTATE_REG_OK, NULL);
cfg->registered=registered;
if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
if (lc->vtable.display_status)
lc->vtable.display_status(lc,msg);
ms_free(msg);
}
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
gstate_new_state(lc, GSTATE_REG_FAILED, msg);
ms_free(msg);
}
static void vfu_request(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
#ifdef VIDEO_ENABLED
if (lc->videostream)
video_stream_send_vfu(lc->videostream);
#endif
}
static void dtmf_received(SalOp *op, char dtmf){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
if (lc->vtable.dtmf_received != NULL)
lc->vtable.dtmf_received(lc, dtmf);
}
static void refer_received(Sal *sal, SalOp *op, const char *referto){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
if (lc->vtable.refer_received)
lc->vtable.refer_received(lc,referto);
}
static void text_received(Sal *sal, const char *from, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
linphone_core_text_received(lc,from,msg);
}
static void notify(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_notify_recv(lc,op,ss,status);
}
static void subscribe_received(SalOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_subscription_new(lc,op,from);
}
static void subscribe_closed(SalOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_subscription_closed(lc,op);
}
static void internal_message(Sal *sal, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
if (lc->vtable.show)
lc->vtable.show(lc);
}
static void ping_reply(SalOp *op){
LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
ms_message("ping reply !");
if (call){
if (call->state==LCStatePreEstablishing){
linphone_core_start_invite(call->core,call,NULL);
}
}
}
SalCallbacks linphone_sal_callbacks={
call_received,
call_ringing,
call_accepted,
call_ack,
call_updated,
call_terminated,
call_failure,
auth_requested,
auth_success,
register_success,
register_failure,
vfu_request,
dtmf_received,
refer_received,
text_received,
notify,
subscribe_received,
subscribe_closed,
internal_message,
ping_reply
};

View file

@ -24,17 +24,16 @@
#include "linphonecore.h"
#include "private.h"
#include <eXosip2/eXosip.h>
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){
LinphoneAddress *parsed_url=NULL;
char *route;
if (linphone_core_interpret_url(lc,to,&parsed_url,&route)){
if ((parsed_url=linphone_core_interpret_url(lc,to))!=NULL){
LinphoneChatRoom *cr=ms_new0(LinphoneChatRoom,1);
cr->lc=lc;
cr->peer=linphone_address_as_string(parsed_url);
cr->peer_url=parsed_url;
cr->route=route;
cr->route=ms_strdup(linphone_core_get_route(lc));
lc->chatrooms=ms_list_append(lc->chatrooms,(void *)cr);
return cr;
}
@ -52,11 +51,10 @@
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){
const char *identity=linphone_core_get_identity(cr->lc);
osip_message_t *sip=NULL;
eXosip_message_build_request(&sip,"MESSAGE",cr->peer,identity,cr->route);
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
eXosip_message_send_request(sip);
SalOp *op=sal_op_new(cr->lc->sal);
sal_op_set_route(op,cr->route);
sal_text_send(op,identity,cr->peer,msg);
}
bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){
@ -69,40 +67,29 @@ void linphone_chat_room_text_received(LinphoneChatRoom *cr, LinphoneCore *lc, co
if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, from, msg);
}
void linphone_core_text_received(LinphoneCore *lc, eXosip_event_t *ev){
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg){
MSList *elem;
const char *msg;
LinphoneChatRoom *cr=NULL;
char *from;
osip_from_t *from_url=ev->request->from;
osip_body_t *body=NULL;
LinphoneAddress *uri;
LinphoneAddress *addr;
char *cleanfrom;
osip_message_get_body(ev->request,0,&body);
if (body==NULL){
ms_error("Could not get text message from SIP body");
return;
}
msg=body->body;
osip_from_to_str(from_url,&from);
uri=linphone_address_new(from);
osip_free(from);
linphone_address_clean(uri);
addr=linphone_address_new(from);
linphone_address_clean(addr);
for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){
cr=(LinphoneChatRoom*)elem->data;
if (linphone_chat_room_matches(cr,uri)){
if (linphone_chat_room_matches(cr,addr)){
break;
}
cr=NULL;
}
from=linphone_address_as_string(uri);
cleanfrom=linphone_address_as_string(addr);
if (cr==NULL){
/* create a new chat room */
cr=linphone_core_create_chat_room(lc,from);
cr=linphone_core_create_chat_room(lc,cleanfrom);
}
linphone_address_destroy(uri);
linphone_chat_room_text_received(cr,lc,from,msg);
ms_free(from);
linphone_address_destroy(addr);
linphone_chat_room_text_received(cr,lc,cleanfrom,msg);
ms_free(cleanfrom);
}

View file

@ -464,7 +464,8 @@ int linphone_set_audio_offer(sdp_context_t *ctx)
elem=lc->codecs_conf.audio_codecs;
while(elem!=NULL){
codec=(PayloadType*) elem->data;
if (linphone_core_check_payload_type_usability(lc,codec) && payload_type_enabled(codec)){
if (linphone_core_check_payload_type_usability(lc,codec) &&
linphone_core_payload_type_enabled(lc,codec)){
sdp_payload_init(&payload);
payload.a_rtpmap=ortp_strdup_printf("%s/%i/1",codec->mime_type,codec->clock_rate);
payload.pt=rtp_profile_get_payload_number_from_rtpmap(lc->local_profile,payload.a_rtpmap);
@ -539,7 +540,8 @@ int linphone_set_video_offer(sdp_context_t *ctx)
for(elem=lc->codecs_conf.video_codecs;elem!=NULL;elem=ms_list_next(elem)){
codec=(PayloadType*) elem->data;
if (linphone_core_check_payload_type_usability(lc,codec) && payload_type_enabled(codec)){
if (linphone_core_check_payload_type_usability(lc,codec) &&
linphone_core_payload_type_enabled(lc,codec)){
sdp_payload_t payload;
sdp_payload_init(&payload);
payload.line=1;
@ -591,7 +593,7 @@ SupportLevel linphone_payload_is_supported(LinphoneCore *lc, sdp_payload_t *payl
ms_warning("payload %s is not usable",rtppayload->mime_type);
return Unsupported;
}
if ( !payload_type_enabled(rtppayload)) {
if ( !linphone_core_payload_type_enabled(lc,rtppayload)) {
ms_warning("payload %s is not enabled.",rtppayload->mime_type);
return Unsupported;
}

View file

@ -31,9 +31,6 @@
const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
const char *str=NULL;
switch(ss){
case LINPHONE_STATUS_UNKNOWN:
str=_("Unknown");
break;
case LINPHONE_STATUS_ONLINE:
str=_("Online");
break;
@ -67,9 +64,6 @@ const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
case LINPHONE_STATUS_PENDING:
str=_("Pending");
break;
case LINPHONE_STATUS_CLOSED:
str=_("Closed");
break;
default:
str=_("Unknown-bug");
}
@ -114,20 +108,20 @@ MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *friend, Linphone
return res;
}
LinphoneFriend *linphone_find_friend_by_nid(MSList *l, int nid){
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){
MSList *elem;
for (elem=l;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend*)elem->data;
if (lf->nid==nid) return lf;
if (lf->insub==op) return lf;
}
return NULL;
}
LinphoneFriend *linphone_find_friend_by_sid(MSList *l, int sid){
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){
MSList *elem;
for (elem=l;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend*)elem->data;
if (lf->sid==sid) return lf;
if (lf->outsub==op) return lf;
}
return NULL;
}
@ -136,30 +130,34 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
char *friend=NULL;
const char *route=NULL;
const char *from=NULL;
osip_message_t *msg=NULL;
LinphoneProxyConfig *cfg;
friend=linphone_address_as_string(fr->uri);
if (fr->proxy!=NULL){
route=fr->proxy->reg_route;
from=fr->proxy->reg_identity;
cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr));
if (cfg!=NULL){
route=linphone_proxy_config_get_route(cfg);
from=linphone_proxy_config_get_identity(cfg);
}else from=linphone_core_get_primary_contact(fr->lc);
if (fr->sid<0){
if (fr->outsub==NULL){
/* people for which we don't have yet an answer should appear as offline */
fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr,friend,_("Gone"),"sip-closed.png");
fr->status=LINPHONE_STATUS_OFFLINE;
/*
if (fr->lc->vtable.notify_recv)
fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
*/
}else{
sal_op_release(fr->outsub);
fr->outsub=NULL;
}
eXosip_lock();
eXosip_subscribe_build_initial_request(&msg,friend,from,route,"presence",600);
eXosip_subscribe_send_initial_request(msg);
eXosip_unlock();
fr->outsub=sal_op_new(fr->lc->sal);
sal_op_set_route(fr->outsub,route);
sal_subscribe_presence(fr->outsub,from,friend);
fr->subscribe_active=TRUE;
ms_free(friend);
}
LinphoneFriend * linphone_friend_new(){
LinphoneFriend *obj=ms_new0(LinphoneFriend,1);
obj->out_did=-1;
obj->in_did=-1;
obj->nid=-1;
obj->sid=-1;
obj->pol=LinphoneSPAccept;
obj->status=LINPHONE_STATUS_OFFLINE;
obj->subscribe=TRUE;
@ -175,6 +173,10 @@ LinphoneFriend *linphone_friend_new_with_addr(const char *addr){
return fr;
}
bool_t linphone_friend_in_list(const LinphoneFriend *lf){
return lf->lc!=NULL;
}
void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result){
LinphoneAddress *fr=NULL;
*result=NULL;
@ -214,6 +216,7 @@ int linphone_friend_set_sip_addr(LinphoneFriend *lf, const char *addr){
ms_warning("Invalid friend sip uri: %s",addr);
return -1;
}
linphone_address_clean(fr);
if (lf->uri!=NULL) linphone_address_destroy(lf->uri);
lf->uri=fr;
return 0;
@ -240,335 +243,84 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri
return 0;
}
int linphone_friend_set_proxy(LinphoneFriend *fr, struct _LinphoneProxyConfig *cfg){
fr->proxy=cfg;
return 0;
SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){
switch(os){
case LINPHONE_STATUS_OFFLINE:
return SalPresenceOffline;
break;
case LINPHONE_STATUS_ONLINE:
return SalPresenceOnline;
break;
case LINPHONE_STATUS_BUSY:
return SalPresenceBusy;
break;
case LINPHONE_STATUS_BERIGHTBACK:
return SalPresenceBerightback;
break;
case LINPHONE_STATUS_AWAY:
return SalPresenceAway;
break;
case LINPHONE_STATUS_ONTHEPHONE:
return SalPresenceOnthephone;
break;
case LINPHONE_STATUS_OUTTOLUNCH:
return SalPresenceOuttolunch;
break;
case LINPHONE_STATUS_NOT_DISTURB:
return SalPresenceDonotdisturb;
break;
case LINPHONE_STATUS_MOVED:
return SalPresenceMoved;
break;
case LINPHONE_STATUS_ALT_SERVICE:
return SalPresenceAltService;
break;
case LINPHONE_STATUS_PENDING:
return SalPresenceOffline;
break;
default:
return SalPresenceOffline;
break;
}
return SalPresenceOffline;
}
void linphone_friend_set_sid(LinphoneFriend *lf, int sid){
lf->sid=sid;
}
void linphone_friend_set_nid(LinphoneFriend *lf, int nid){
lf->nid=nid;
lf->inc_subscribe_pending=TRUE;
}
void add_presence_body(osip_message_t *notify, LinphoneOnlineStatus online_status)
{
char buf[1000];
#ifdef SUPPORT_MSN
int atom_id = 1000;
#endif
char *contact_info;
osip_contact_t *ct=NULL;
osip_message_get_contact(notify,0,&ct);
osip_contact_to_str(ct,&contact_info);
#ifdef SUPPORT_MSN
if (online_status==LINPHONE_STATUS_ONLINE)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"online\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==LINPHONE_STATUS_BUSY)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inuse\" />\n\
<msnsubstatus substatus=\"busy\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==LINPHONE_STATUS_BERIGHTBACK)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"berightback\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==LINPHONE_STATUS_AWAY)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"away\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==LINPHONE_STATUS_ONTHEPHONE)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inuse\" />\n\
<msnsubstatus substatus=\"onthephone\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==LINPHONE_STATUS_OUTTOLUNCH)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"outtolunch\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"away\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
osip_message_set_body(notify, buf, strlen(buf));
osip_message_set_content_type(notify, "application/xpidf+xml");
#else
if (online_status==LINPHONE_STATUS_ONLINE)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>online</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==LINPHONE_STATUS_BUSY)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>busy</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>busy</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==LINPHONE_STATUS_BERIGHTBACK)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>in-transit</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>be right back</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==LINPHONE_STATUS_AWAY)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>away</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>away</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==LINPHONE_STATUS_ONTHEPHONE)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>on-the-phone</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>on the phone</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==LINPHONE_STATUS_OUTTOLUNCH)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>meal</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>out to lunch</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else
{
/* */
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n%s",
contact_info,
"<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>closed</basic>\n\
<es:activities>\n\
<es:activity>permanent-absence</es:activity>\n\
</es:activities>\n\
</status>\n\
</tuple>\n\
\n</presence>\n");
}
osip_message_set_body(notify, buf, strlen(buf));
osip_message_set_content_type(notify, "application/pidf+xml");
#endif
osip_free(contact_info);
}
void linphone_friend_notify(LinphoneFriend *lf, int ss, LinphoneOnlineStatus os){
void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){
//printf("Wish to notify %p, lf->nid=%i\n",lf,lf->nid);
if (lf->in_did!=-1){
osip_message_t *msg=NULL;
const char *identity;
if (lf->proxy!=NULL) identity=lf->proxy->reg_identity;
else identity=linphone_core_get_primary_contact(lf->lc);
eXosip_lock();
eXosip_insubscription_build_notify(lf->in_did,ss,0,&msg);
if (msg!=NULL){
osip_message_set_contact(msg,identity);
add_presence_body(msg,os);
eXosip_insubscription_send_request(lf->in_did,msg);
}else ms_error("could not create notify for incoming subscription.");
eXosip_unlock();
if (lf->insub!=NULL){
sal_notify_presence(lf->insub,linphone_online_status_to_sal(os),NULL);
}
}
static void linphone_friend_unsubscribe(LinphoneFriend *lf){
if (lf->out_did!=-1) {
osip_message_t *msg=NULL;
eXosip_lock();
eXosip_subscribe_build_refresh_request(lf->out_did,&msg);
if (msg){
osip_message_set_expires(msg,"0");
eXosip_subscribe_send_refresh_request(lf->out_did,msg);
}else ms_error("Could not build subscribe refresh request !");
eXosip_unlock();
if (lf->outsub!=NULL) {
sal_unsubscribe(lf->outsub);
sal_op_release(lf->outsub);
lf->outsub=NULL;
lf->subscribe_active=FALSE;
}
}
void linphone_friend_close_subscriptions(LinphoneFriend *lf){
linphone_friend_unsubscribe(lf);
if (lf->insub){
sal_notify_close(lf->insub);
sal_op_release(lf->insub);
lf->insub=NULL;
}
}
void linphone_friend_destroy(LinphoneFriend *lf){
linphone_friend_notify(lf,EXOSIP_SUBCRSTATE_TERMINATED,LINPHONE_STATUS_CLOSED);
linphone_friend_unsubscribe(lf);
if (lf->uri!=NULL) linphone_address_destroy(lf->uri);
if (lf->info!=NULL) buddy_info_free(lf->info);
ms_free(lf);
}
void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, LinphoneProxyConfig *cfg){
if (lf->proxy==cfg){
lf->proxy=NULL;
}
}
const LinphoneAddress *linphone_friend_get_uri(const LinphoneFriend *lf){
const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf){
return lf->uri;
}
bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){
return lf->subscribe;
}
@ -597,22 +349,22 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
if (fr->inc_subscribe_pending){
switch(fr->pol){
case LinphoneSPWait:
linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_PENDING,LINPHONE_STATUS_PENDING);
linphone_friend_notify(fr,LINPHONE_STATUS_PENDING);
break;
case LinphoneSPAccept:
if (fr->lc!=NULL)
{
linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_ACTIVE,fr->lc->presence_mode);
linphone_friend_notify(fr,fr->lc->presence_mode);
}
break;
case LinphoneSPDeny:
linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_TERMINATED,LINPHONE_STATUS_CLOSED);
linphone_friend_notify(fr,LINPHONE_STATUS_OFFLINE);
break;
}
fr->inc_subscribe_pending=FALSE;
}
if (fr->subscribe && fr->out_did==-1){
if (fr->subscribe && fr->subscribe_active==FALSE){
ms_message("Sending a new SUBSCRIBE");
__linphone_friend_do_subscribe(fr);
}
ms_message("linphone_friend_apply() done.");
@ -632,6 +384,14 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf)
{
ms_return_if_fail(lf->lc==NULL);
ms_return_if_fail(lf->uri!=NULL);
if (ms_list_find(lc->friends,lf)!=NULL){
char *tmp=NULL;
const LinphoneAddress *addr=linphone_friend_get_address(lf);
if (addr) tmp=linphone_address_as_string(addr);
ms_warning("Friend %s already in list, ignored.", tmp ? tmp : "unknown");
if (tmp) ms_free(tmp);
return ;
}
lc->friends=ms_list_append(lc->friends,lf);
linphone_friend_apply(lf,lc);
return ;
@ -667,7 +427,7 @@ static bool_t username_match(const char *u1, const char *u2){
return FALSE;
}
LinphoneFriend *linphone_core_get_friend_by_uri(const LinphoneCore *lc, const char *uri){
LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *uri){
LinphoneAddress *puri=linphone_address_new(uri);
const MSList *elem;
const char *username=linphone_address_get_username(puri);
@ -752,10 +512,6 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde
a=lp_config_get_int(config,item,"subscribe",0);
linphone_friend_send_subscribe(lf,a);
a=lp_config_get_int(config,item,"proxy",-1);
if (a!=-1) {
linphone_friend_set_proxy(lf,__index_to_proxy(lc,a));
}
linphone_friend_set_ref_key(lf,lp_config_get_string(config,item,"refkey",NULL));
return lf;
}
@ -779,7 +535,6 @@ const char *__policy_enum_to_str(LinphoneSubscribePolicy pol){
void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, int index){
char key[50];
char *tmp;
int a;
const char *refkey;
sprintf(key,"friend_%i",index);
@ -798,10 +553,6 @@ void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf,
}
lp_config_set_string(config,key,"pol",__policy_enum_to_str(lf->pol));
lp_config_set_int(config,key,"subscribe",lf->subscribe);
if (lf->proxy!=NULL){
a=ms_list_index(lf->lc->sip_conf.proxies,lf->proxy);
lp_config_set_int(config,key,"proxy",a);
}else lp_config_set_int(config,key,"proxy",-1);
refkey=linphone_friend_get_ref_key(lf);
if (refkey){

View file

@ -24,7 +24,7 @@
#include "linphonecore.h"
#include "private.h"
#if 0
static const char *_gstates_text[] = {
"GSTATE_POWER_OFF", /* 0 */

File diff suppressed because it is too large Load diff

View file

@ -39,109 +39,10 @@ extern "C" {
struct _MSSndCard;
struct _LinphoneCore;
bool_t payload_type_enabled(struct _PayloadType *pt);
void payload_type_set_enable(struct _PayloadType *pt,int value);
const char *payload_type_get_description(struct _PayloadType *pt);
struct SalOp;
struct _LpConfig;
typedef struct sip_config
{
char *contact;
char *guessed_contact;
int sip_port;
MSList *proxies;
MSList *deleted_proxies;
int inc_timeout; /*timeout after an un-answered incoming call is rejected*/
bool_t use_info;
bool_t use_rfc2833; /*force RFC2833 to be sent*/
bool_t guess_hostname;
bool_t loopback_only;
bool_t ipv6_enabled;
bool_t sdp_200_ack;
bool_t only_one_codec; /*in SDP answers*/
bool_t register_only_when_network_is_up;
} sip_config_t;
typedef struct rtp_config
{
int audio_rtp_port;
int video_rtp_port;
int audio_jitt_comp; /*jitter compensation*/
int video_jitt_comp; /*jitter compensation*/
int nortp_timeout;
}rtp_config_t;
typedef struct net_config
{
char *nat_address;
char *stun_server;
char *relay;
int download_bw;
int upload_bw;
int firewall_policy;
int mtu;
bool_t nat_sdp_only;
}net_config_t;
typedef struct sound_config
{
struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */
struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */
struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */
const char **cards;
int latency; /* latency in samples of the current used sound device */
char rec_lev;
char play_lev;
char ring_lev;
char source;
char *local_ring;
char *remote_ring;
bool_t ec;
bool_t ea;
bool_t agc;
} sound_config_t;
typedef struct codecs_config
{
MSList *audio_codecs; /* list of audio codecs in order of preference*/
MSList *video_codecs; /* for later use*/
}codecs_config_t;
typedef struct video_config{
struct _MSWebCam *device;
const char **cams;
MSVideoSize vsize;
bool_t capture;
bool_t show_local;
bool_t display;
bool_t selfview; /*during calls*/
}video_config_t;
typedef struct ui_config
{
int is_daemon;
int is_applet;
unsigned int timer_id; /* the timer id for registration */
}ui_config_t;
typedef struct autoreplier_config
{
int enabled;
int after_seconds; /* accept the call after x seconds*/
int max_users; /* maximum number of user that can call simultaneously */
int max_rec_time; /* the max time of incoming voice recorded */
int max_rec_msg; /* maximum number of recorded messages */
const char *message; /* the path of the file to be played */
}autoreplier_config_t;
struct osip_from;
/**
* Object that represents a SIP address.
@ -157,7 +58,7 @@ struct osip_from;
* @ingroup linphone_address
* @var LinphoneAddress
*/
typedef struct osip_from LinphoneAddress;
typedef struct SalAddress LinphoneAddress;
LinphoneAddress * linphone_address_new(const char *uri);
LinphoneAddress * linphone_address_clone(const LinphoneAddress *uri);
@ -176,8 +77,6 @@ char *linphone_address_as_string(const LinphoneAddress *u);
char *linphone_address_as_string_uri_only(const LinphoneAddress *u);
void linphone_address_destroy(LinphoneAddress *u);
struct _LinphoneCore;
struct _sdp_context;
struct _SipSetupContext;
struct _LinphoneCall;
@ -240,7 +139,7 @@ typedef enum{
}LinphoneSubscribePolicy;
typedef enum _LinphoneOnlineStatus{
LINPHONE_STATUS_UNKNOWN,
LINPHONE_STATUS_OFFLINE,
LINPHONE_STATUS_ONLINE,
LINPHONE_STATUS_BUSY,
LINPHONE_STATUS_BERIGHTBACK,
@ -250,29 +149,15 @@ typedef enum _LinphoneOnlineStatus{
LINPHONE_STATUS_NOT_DISTURB,
LINPHONE_STATUS_MOVED,
LINPHONE_STATUS_ALT_SERVICE,
LINPHONE_STATUS_OFFLINE,
LINPHONE_STATUS_PENDING,
LINPHONE_STATUS_CLOSED,
LINPHONE_STATUS_END
}LinphoneOnlineStatus;
const char *linphone_online_status_to_string(LinphoneOnlineStatus ss);
typedef struct _LinphoneFriend{
LinphoneAddress *uri;
int in_did;
int out_did;
int sid;
int nid;
LinphoneSubscribePolicy pol;
LinphoneOnlineStatus status;
struct _LinphoneProxyConfig *proxy;
struct _LinphoneCore *lc;
BuddyInfo *info;
char *refkey;
bool_t subscribe;
bool_t inc_subscribe_pending;
}LinphoneFriend;
struct _LinphoneFriend;
typedef struct _LinphoneFriend LinphoneFriend;
LinphoneFriend * linphone_friend_new();
LinphoneFriend *linphone_friend_new_with_addr(const char *addr);
@ -280,21 +165,21 @@ int linphone_friend_set_sip_addr(LinphoneFriend *fr, const char *uri);
int linphone_friend_set_name(LinphoneFriend *fr, const char *name);
int linphone_friend_send_subscribe(LinphoneFriend *fr, bool_t val);
int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol);
int linphone_friend_set_proxy(LinphoneFriend *fr, struct _LinphoneProxyConfig *cfg);
void linphone_friend_edit(LinphoneFriend *fr);
void linphone_friend_done(LinphoneFriend *fr);
void linphone_friend_destroy(LinphoneFriend *lf);
const LinphoneAddress *linphone_friend_get_uri(const LinphoneFriend *lf);
const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf);
bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf);
LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf);
LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf);
BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf);
void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key);
const char *linphone_friend_get_ref_key(const LinphoneFriend *lf);
#define linphone_friend_in_list(lf) ((lf)->lc!=NULL)
bool_t linphone_friend_in_list(const LinphoneFriend *lf);
#define linphone_friend_url(lf) ((lf)->url)
/**
* @addtogroup proxies
* @{
@ -315,33 +200,12 @@ const char *linphone_friend_get_ref_key(const LinphoneFriend *lf);
* The default proxy (see linphone_core_set_default_proxy() ) is the one of the list
* that is used by default for calls.
**/
typedef struct _LinphoneProxyConfig
{
struct _LinphoneCore *lc;
char *reg_proxy;
char *reg_identity;
char *reg_route;
char *realm;
int expires;
int reg_time;
int rid;
char *type;
struct _SipSetupContext *ssctx;
int auth_failures;
char *contact_addr; /* our IP address as seen by the proxy, read from via 's received= parameter*/
int contact_port; /*our IP port as seen by the proxy, read from via's rport= parameter */
char *dial_prefix;
bool_t commit;
bool_t reg_sendregister;
bool_t registered;
bool_t publish;
bool_t dial_escape_plus;
} LinphoneProxyConfig;
typedef struct _LinphoneProxyConfig LinphoneProxyConfig;
LinphoneProxyConfig *linphone_proxy_config_new(void);
int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr);
void linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity);
void linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route);
int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity);
int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route);
void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int expires);
void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val);
#define linphone_proxy_config_enableregister linphone_proxy_config_enable_register
@ -353,18 +217,15 @@ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char
bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj);
const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg);
/** Returns the proxy configured identity as a const char * */
#define linphone_proxy_config_get_route(obj) ((obj)->reg_route)
/** Returns the proxy configured identity as a const char * */
#define linphone_proxy_config_get_identity(obj) ((obj)->reg_identity)
#define linphone_proxy_config_publish_enabled(obj) ((obj)->publish)
/** Returns the proxy sip address as const char * */
#define linphone_proxy_config_get_addr(obj) ((obj)->reg_proxy)
/** Returns the 'expire' time of the registration */
#define linphone_proxy_config_get_expires(obj) ((obj)->expires)
/** Returns TRUE if registration is enabled, FALSE otherwise */
#define linphone_proxy_config_register_enabled(obj) ((obj)->reg_sendregister)
#define linphone_proxy_config_get_core(obj) ((obj)->lc)
const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj);
const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj);
bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj);
const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj);
int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj);
bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj);
struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj);
bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg);
const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg);
@ -377,6 +238,14 @@ SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg);
* normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222
*/
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len);
/*
* attached a user data to a proxy config
*/
void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud);
/*
* get user data to a proxy config. return null if any
*/
void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr);
/**
* @}
@ -401,6 +270,8 @@ int linphone_account_creator_test_existence(LinphoneAccountCreator *obj);
LinphoneProxyConfig * linphone_account_creator_validate(LinphoneAccountCreator *obj);
void linphone_account_creator_destroy(LinphoneAccountCreator *obj);
struct _LinphoneAuthInfo;
/**
* @ingroup authentication
* Object holding authentication information.
@ -425,33 +296,23 @@ void linphone_account_creator_destroy(LinphoneAccountCreator *obj);
* transactions and retry them with authentication headers.
*
**/
typedef struct _LinphoneAuthInfo
{
char *username;
char *realm;
char *userid;
char *passwd;
char *ha1;
bool_t works;
bool_t first_time;
}LinphoneAuthInfo;
typedef struct _LinphoneAuthInfo LinphoneAuthInfo;
LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid,
const char *passwd, const char *ha1,const char *realm);
void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd);
void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username);
void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid);
const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i);
const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i);
const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i);
/* you don't need those function*/
void linphone_auth_info_destroy(LinphoneAuthInfo *info);
LinphoneAuthInfo * linphone_auth_info_new_from_config_file(struct _LpConfig *config, int pos);
struct _LinphoneChatRoom{
struct _LinphoneCore *lc;
char *peer;
char *route;
LinphoneAddress *peer_url;
void * user_data;
};
struct _LinphoneChatRoom;
typedef struct _LinphoneChatRoom LinphoneChatRoom;
LinphoneChatRoom * linphone_core_create_chat_room(struct _LinphoneCore *lc, const char *to);
@ -523,7 +384,7 @@ typedef void (*DisplayQuestionCb)(struct _LinphoneCore *lc, const char *message)
/** Callback prototype */
typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data);
/** Callback prototype */
typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img);
typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid);
/** Callback prototype */
typedef void (*NewUnknownSubscriberCb)(struct _LinphoneCore *lc, LinphoneFriend *lf, const char *url);
/** Callback prototype */
@ -555,10 +416,6 @@ typedef struct _LinphoneVTable
AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */
DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/
DisplayMessageCb display_message;/**< Callback to display a message to the user */
#ifdef VINCENT_MAURY_RSVP
/* the yes/no dialog box */
DisplayMessageCb display_yes_no;
#endif
DisplayMessageCb display_warning;/** Callback to display a warning to the user */
DisplayUrlCb display_url;
DisplayQuestionCb display_question;
@ -595,77 +452,13 @@ typedef enum _LinphoneWaitingState{
} LinphoneWaitingState;
typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *context, LinphoneWaitingState ws, const char *purpose, float progress);
typedef struct _LinphoneCore
{
LinphoneCoreVTable vtable;
struct _LpConfig *config;
net_config_t net_conf;
sip_config_t sip_conf;
rtp_config_t rtp_conf;
sound_config_t sound_conf;
video_config_t video_conf;
codecs_config_t codecs_conf;
ui_config_t ui_conf;
autoreplier_config_t autoreplier_conf;
LinphoneProxyConfig *default_proxy;
MSList *friends;
MSList *auth_info;
struct _RingStream *ringstream;
LCCallbackObj preview_finished_cb;
bool_t preview_finished;
struct _LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/
int rid; /*registration id*/
MSList *queued_calls; /* used by the autoreplier */
MSList *call_logs;
MSList *chatrooms;
int max_call_logs;
int missed_calls;
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
struct _VideoStream *previewstream;
RtpTransport *a_rtp,*a_rtcp;
struct _RtpProfile *local_profile;
MSList *bl_reqs;
MSList *subscribers; /* unknown subscribers */
int minutes_away;
LinphoneOnlineStatus presence_mode;
LinphoneOnlineStatus prev_mode;
char *alt_contact;
void *data;
ms_mutex_t lock;
char *play_file;
char *rec_file;
time_t prevtime;
int dw_audio_bw;
int up_audio_bw;
int dw_video_bw;
int up_video_bw;
int audio_bw;
int automatic_action;
gstate_t gstate_power;
gstate_t gstate_reg;
gstate_t gstate_call;
LinphoneWaitingCallback wait_cb;
void *wait_ctx;
bool_t use_files;
bool_t apply_nat_settings;
bool_t ready;
bool_t bl_refresh;
#ifdef VINCENT_MAURY_RSVP
/* QoS parameters*/
int rsvp_enable;
int rpc_enable;
#endif
typedef struct _LinphoneCore LinphoneCore;
/*set this field to false if application manage network connection state
* In case of false, network state must be communicate to linphone core with method linphone_core_
*/
bool_t auto_net_state_mon;
bool_t network_reachable;
int down_ptime;
} LinphoneCore;
/* THE main API */
@ -682,8 +475,12 @@ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
/* function to be periodically called in a main loop */
void linphone_core_iterate(LinphoneCore *lc);
LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url);
int linphone_core_invite(LinphoneCore *lc, const char *url);
int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr);
int linphone_core_refer(LinphoneCore *lc, const char *url);
bool_t linphone_core_inc_invite_pending(LinphoneCore*lc);
@ -742,6 +539,12 @@ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc);
int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs);
bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt);
int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable);
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt);
bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt);
int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
@ -828,6 +631,18 @@ int linphone_core_get_play_level(LinphoneCore *lc);
int linphone_core_get_rec_level(LinphoneCore *lc);
void linphone_core_set_ring_level(LinphoneCore *lc, int level);
void linphone_core_set_play_level(LinphoneCore *lc, int level);
/**
* Allow to control play level before entering sound card: level in db
*
* @ingroup media_parameters
**/
void linphone_core_set_soft_play_level(LinphoneCore *lc, float level);
/**
* get play level before entering sound card: level in db
*
* @ingroup media_parameters
**/
float linphone_core_get_soft_play_level(LinphoneCore *lc);
void linphone_core_set_rec_level(LinphoneCore *lc, int level);
const char * linphone_core_get_ringer_device(LinphoneCore *lc);
const char * linphone_core_get_playback_device(LinphoneCore *lc);
@ -852,6 +667,12 @@ void linphone_core_enable_agc(LinphoneCore *lc, bool_t val);
bool_t linphone_core_agc_enabled(const LinphoneCore *lc);
void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted);
/**
* return mic state.
*
* @ingroup media_parameters
**/
bool_t linphone_core_is_mic_muted(LinphoneCore *lc);
void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *contact,LinphoneOnlineStatus os);
@ -865,7 +686,7 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf);
const MSList * linphone_core_get_friend_list(const LinphoneCore *lc);
/* notify all friends that have subscribed */
void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os);
LinphoneFriend *linphone_core_get_friend_by_uri(const LinphoneCore *lc, const char *uri);
LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr);
LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key);
/* returns a list of LinphoneCallLog */
@ -927,8 +748,6 @@ void linphone_core_set_mtu(LinphoneCore *lc, int mtu);
void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value);
bool_t linphone_core_is_in_main_thread(LinphoneCore *lc);
void *linphone_core_get_user_data(LinphoneCore *lc);
/* returns LpConfig object to read/write to the config file: usefull if you wish to extend
@ -954,21 +773,6 @@ void linphone_core_destroy(LinphoneCore *lc);
/*for advanced users:*/
void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, RtpTransport *rtcp);
/* end of lecacy api */
/*internal use only */
#define linphone_core_lock(lc) ms_mutex_lock(&(lc)->lock)
#define linphone_core_unlock(lc) ms_mutex_unlock((&lc)->lock)
void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
void linphone_core_stop_media_streams(LinphoneCore *lc);
const char * linphone_core_get_identity(LinphoneCore *lc);
const char * linphone_core_get_route(LinphoneCore *lc);
bool_t linphone_core_interpret_url(LinphoneCore *lc, const char *url, LinphoneAddress **real_parsed_url, char **route);
void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose);
void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses);
void linphone_core_stop_waiting(LinphoneCore *lc);
#ifdef __cplusplus
}
#endif

View file

@ -42,8 +42,7 @@ static void linphone_android_log_handler(OrtpLogLevel lev, const char *fmt, va_l
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved)
{
#ifdef ANDROID
linphone_core_enable_logs_with_cb(linphone_android_log_handler);
#ifdef ANDROID
ms_andsnd_register_card(ajvm);
#endif /*ANDROID*/
jvm=ajvm;
@ -51,7 +50,16 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved)
}
//LinphoneFactory
extern "C" void Java_org_linphone_core_LinphoneCoreFactory_setDebugMode(JNIEnv* env
,jobject thiz
,jboolean isDebug) {
if (isDebug) {
linphone_core_enable_logs_with_cb(linphone_android_log_handler);
} else {
linphone_core_disable_logs();
}
}
// LinphoneCore
class LinphoneCoreData {
@ -150,6 +158,9 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv*
const char* userConfig = env->GetStringUTFChars(juserConfig, NULL);
const char* factoryConfig = env->GetStringUTFChars(jfactoryConfig, NULL);
LinphoneCoreData* ldata = new LinphoneCoreData(env,thiz,jlistener,juserdata);
#ifdef ANDROID
ms_andsnd_register_card(jvm);
#endif /*ANDROID*/
jlong nativePtr = (jlong)linphone_core_new( &ldata->vTable
,userConfig
,factoryConfig
@ -191,8 +202,12 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getDefaultProxyConfig(
extern "C" int Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv* env
,jobject thiz
,jobject jproxyCfg
,jlong lc
,jlong pc) {
LinphoneProxyConfig* proxy = (LinphoneProxyConfig*)pc;
linphone_proxy_config_set_user_data(proxy, env->NewGlobalRef(jproxyCfg));
return linphone_core_add_proxy_config((LinphoneCore*)lc,(LinphoneProxyConfig*)pc);
}
@ -219,6 +234,12 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_invite( JNIEnv* env
linphone_core_invite((LinphoneCore*)lc,uri);
env->ReleaseStringUTFChars(juri, uri);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_inviteAddress( JNIEnv* env
,jobject thiz
,jlong lc
,jlong to) {
linphone_core_invite_address((LinphoneCore*)lc,(LinphoneAddress*)to);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall( JNIEnv* env
,jobject thiz
@ -268,11 +289,59 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setNetworkStateReachable
linphone_core_set_network_reachable((LinphoneCore*)lc,isReachable);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setSoftPlayLevel( JNIEnv* env
,jobject thiz
,jlong lc
,jfloat gain) {
linphone_core_set_soft_play_level((LinphoneCore*)lc,gain);
}
extern "C" float Java_org_linphone_core_LinphoneCoreImpl_getSoftPlayLevel( JNIEnv* env
,jobject thiz
,jlong lc) {
return linphone_core_get_soft_play_level((LinphoneCore*)lc);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_muteMic( JNIEnv* env
,jobject thiz
,jlong lc
,jboolean isMuted) {
linphone_core_mute_mic((LinphoneCore*)lc,isMuted);
}
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_interpretUrl( JNIEnv* env
,jobject thiz
,jlong lc
,jstring jurl) {
const char* url = env->GetStringUTFChars(jurl, NULL);
jlong result = (jlong)linphone_core_interpret_url((LinphoneCore*)lc,url);
env->ReleaseStringUTFChars(jurl, url);
return result;
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_sendDtmf( JNIEnv* env
,jobject thiz
,jlong lc
,jchar dtmf) {
linphone_core_send_dtmf((LinphoneCore*)lc,dtmf);
}
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearCallLogs(JNIEnv* env
,jobject thiz
,jlong lc) {
linphone_core_clear_call_logs((LinphoneCore*)lc);
}
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isMicMuted( JNIEnv* env
,jobject thiz
,jlong lc) {
return linphone_core_is_mic_muted((LinphoneCore*)lc);
}
//ProxyConfig
extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) {
return (jlong) linphone_proxy_config_new();
LinphoneProxyConfig* proxy = linphone_proxy_config_new();
return (jlong) proxy;
}
extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_delete(JNIEnv* env,jobject thiz,jlong ptr) {
@ -417,7 +486,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv*
}
}
extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toUri(JNIEnv* env
extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toString(JNIEnv* env
,jobject thiz
,jlong ptr) {
char* uri = linphone_address_as_string((LinphoneAddress*)ptr);
@ -425,6 +494,23 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toUri(JNIEnv* env
ms_free(uri);
return juri;
}
extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toUri(JNIEnv* env
,jobject thiz
,jlong ptr) {
char* uri = linphone_address_as_string_uri_only((LinphoneAddress*)ptr);
jstring juri =env->NewStringUTF(uri);
ms_free(uri);
return juri;
}
extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDisplayName(JNIEnv* env
,jobject thiz
,jlong address
,jstring jdisplayName) {
const char* displayName = env->GetStringUTFChars(jdisplayName, NULL);
linphone_address_set_display_name((LinphoneAddress*)address,displayName);
env->ReleaseStringUTFChars(jdisplayName, displayName);
}
//CallLog
extern "C" jlong Java_org_linphone_core_LinphoneCallLogImpl_getFrom(JNIEnv* env

View file

@ -170,21 +170,42 @@ void check_sound_device(LinphoneCore *lc)
#define RTP_HDR_SZ 12
#define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/
const char *payload_type_get_description(PayloadType *pt){
return _((const char *)pt->user_data);
}
void payload_type_set_enable(PayloadType *pt,int value)
static void payload_type_set_enable(PayloadType *pt,int value)
{
if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \
else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED);
}
bool_t payload_type_enabled(PayloadType *pt) {
static bool_t payload_type_enabled(PayloadType *pt) {
return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
}
bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt){
if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
return payload_type_enabled(pt);
}
ms_error("Getting enablement status of codec not in audio or video list of PayloadType !");
return FALSE;
}
int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){
if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
payload_type_set_enable(pt,enabled);
return 0;
}
ms_error("Enabling codec not in audio or video list of PayloadType !");
return -1;
}
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
if (ms_filter_codec_supported(pt->mime_type)){
MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
return _(desc->text);
}
return NULL;
}
/*this function makes a special case for speex/8000.
This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
@ -255,6 +276,12 @@ bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType
case PAYLOAD_AUDIO_PACKETIZED:
codec_band=get_audio_payload_bandwidth(lc,pt);
ret=bandwidth_is_greater(min_audio_bw*1000,codec_band);
/*hack to avoid using uwb codecs when having low bitrate and video*/
if (bandwidth_is_greater(199,min_audio_bw)){
if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
ret=FALSE;
}
}
//ms_message("Payload %s: %g",pt->mime_type,codec_band);
break;
case PAYLOAD_VIDEO:
@ -274,152 +301,6 @@ bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType
return ret;
}
static PayloadType * find_payload(RtpProfile *prof, PayloadType *pt /*from config*/){
PayloadType *candidate=NULL;
int i;
PayloadType *it;
for(i=0;i<127;++i){
it=rtp_profile_get_payload(prof,i);
if (it!=NULL && strcasecmp(pt->mime_type,it->mime_type)==0
&& (pt->clock_rate==it->clock_rate || pt->clock_rate<=0)
&& payload_type_get_user_data(it)==NULL ){
if ( (pt->recv_fmtp && it->recv_fmtp && strcasecmp(pt->recv_fmtp,it->recv_fmtp)==0) ||
(pt->recv_fmtp==NULL && it->recv_fmtp==NULL) ){
/*exact match*/
return it;
}else candidate=it;
}
}
return candidate;
}
static bool_t check_h264_packmode(PayloadType *payload, MSFilterDesc *desc){
if (payload->recv_fmtp==NULL || strstr(payload->recv_fmtp,"packetization-mode")==0){
/*this is packetization-mode=0 H264, we only support it with a multislicing
enabled version of x264*/
if (strstr(desc->text,"x264") && strstr(desc->text,"multislicing")==0){
/*this is x264 without multisclicing*/
ms_message("Disabling packetization-mode=0 H264 codec because "
"of lack of multislicing support");
return FALSE;
}
}
return TRUE;
}
static MSList *fix_codec_list(RtpProfile *prof, MSList *conflist)
{
MSList *elem;
MSList *newlist=NULL;
PayloadType *payload,*confpayload;
for (elem=conflist;elem!=NULL;elem=ms_list_next(elem))
{
confpayload=(PayloadType*)elem->data;
payload=find_payload(prof,confpayload);
if (payload!=NULL){
if (ms_filter_codec_supported(confpayload->mime_type)){
MSFilterDesc *desc=ms_filter_get_encoder(confpayload->mime_type);
if (strcasecmp(confpayload->mime_type,"H264")==0){
if (!check_h264_packmode(confpayload,desc)){
continue;
}
}
payload_type_set_user_data(payload,(void*)desc->text);
payload_type_set_enable(payload,payload_type_enabled(confpayload));
newlist=ms_list_append(newlist,payload);
}
}
else{
ms_warning("Cannot support %s/%i: does not exist.",confpayload->mime_type,
confpayload->clock_rate);
}
}
return newlist;
}
void linphone_core_setup_local_rtp_profile(LinphoneCore *lc)
{
int i;
MSList *audiopt,*videopt;
PayloadType *payload;
bool_t prepend;
lc->local_profile=rtp_profile_clone_full(&av_profile);
/* first look at the list given by configuration file to see if
it is correct */
audiopt=fix_codec_list(lc->local_profile,lc->codecs_conf.audio_codecs);
videopt=fix_codec_list(lc->local_profile,lc->codecs_conf.video_codecs);
/* now find and add payloads that are not listed in the configuration
codec list */
for (i=0;i<127;i++)
{
payload=rtp_profile_get_payload(lc->local_profile,i);
if (payload!=NULL){
if (payload_type_get_user_data(payload)!=NULL) continue;
/* find a mediastreamer codec for this payload type */
if (ms_filter_codec_supported(payload->mime_type)){
MSFilterDesc *desc=ms_filter_get_encoder(payload->mime_type);
ms_message("Adding new codec %s/%i",payload->mime_type,payload->clock_rate);
payload_type_set_enable(payload,1);
payload_type_set_user_data(payload,(void *)desc->text);
prepend=FALSE;
/* by default, put speex, mpeg4, or h264 on top of list*/
if (strcmp(payload->mime_type,"speex")==0)
prepend=TRUE;
else if (strcmp(payload->mime_type,"MP4V-ES")==0)
prepend=TRUE;
else if (strcasecmp(payload->mime_type,"H264")==0){
if (check_h264_packmode(payload,desc))
prepend=TRUE;
else continue;
}
switch (payload->type){
case PAYLOAD_AUDIO_CONTINUOUS:
case PAYLOAD_AUDIO_PACKETIZED:
if (prepend)
audiopt=ms_list_prepend(audiopt,(void *)payload);
else
audiopt=ms_list_append(audiopt,(void *)payload);
break;
case PAYLOAD_VIDEO:
if (prepend)
videopt=ms_list_prepend(videopt,(void *)payload);
else
videopt=ms_list_append(videopt,(void *)payload);
break;
default:
ms_error("Unsupported rtp media type.");
}
}
}
}
ms_list_for_each(lc->codecs_conf.audio_codecs,(void (*)(void*))payload_type_destroy);
ms_list_for_each(lc->codecs_conf.video_codecs,(void (*)(void *))payload_type_destroy);
ms_list_free(lc->codecs_conf.audio_codecs);
ms_list_free(lc->codecs_conf.video_codecs);
/* set the fixed lists instead:*/
lc->codecs_conf.audio_codecs=audiopt;
lc->codecs_conf.video_codecs=videopt;
linphone_core_update_allocated_audio_bandwidth(lc);
}
int from_2char_without_params(osip_from_t *from,char **str)
{
osip_from_t *tmpfrom=NULL;
osip_from_clone(from,&tmpfrom);
if (tmpfrom!=NULL){
while(!osip_list_eol(&tmpfrom->gen_params,0)){
osip_generic_param_t *param=(osip_generic_param_t*)osip_list_get(&tmpfrom->gen_params,0);
osip_generic_param_free(param);
osip_list_remove(&tmpfrom->gen_params,0);
}
}else return -1;
osip_from_to_str(tmpfrom,str);
osip_from_free(tmpfrom);
return 0;
}
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
#if !defined(_WIN32_WCE)
FILE *f=popen(command,"r");
@ -598,6 +479,11 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
bool_t got_audio,got_video;
bool_t cone_audio=FALSE,cone_video=FALSE;
struct timeval init,cur;
SalEndpointCandidate *ac,*vc;
ac=&call->localdesc->streams[0].candidates[0];
vc=&call->localdesc->streams[1].candidates[0];
if (parse_stun_server_addr(server,&ss,&ss_len)<0){
ms_error("Fail to parser stun server address: %s",server);
return;
@ -630,20 +516,20 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
usleep(10000);
#endif
if (recvStunResponse(sock1,call->audio_params.natd_addr,
&call->audio_params.natd_port,&id)>0){
if (recvStunResponse(sock1,ac->addr,
&ac->port,&id)>0){
ms_message("STUN test result: local audio port maps to %s:%i",
call->audio_params.natd_addr,
call->audio_params.natd_port);
ac->addr,
ac->port);
if (id==11)
cone_audio=TRUE;
got_audio=TRUE;
}
if (recvStunResponse(sock2,call->video_params.natd_addr,
&call->video_params.natd_port,&id)>0){
if (recvStunResponse(sock2,vc->addr,
&vc->port,&id)>0){
ms_message("STUN test result: local video port maps to %s:%i",
call->video_params.natd_addr,
call->video_params.natd_port);
vc->addr,
vc->port);
if (id==22)
cone_video=TRUE;
got_video=TRUE;
@ -657,7 +543,8 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
}else{
if (!cone_audio) {
ms_warning("NAT is symmetric for audio port");
call->audio_params.natd_port=0;
ac->addr[0]='\0';
ac->port=0;
}
}
if (sock2>=0){
@ -666,7 +553,8 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
}else{
if (!cone_video) {
ms_warning("NAT is symmetric for video port.");
call->video_params.natd_port=0;
vc->addr[0]='\0';
vc->port=0;
}
}
}

164
coreapi/offeranswer.c Normal file
View file

@ -0,0 +1,164 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sal.h"
#include "offeranswer.h"
static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){
PayloadType *pt;
char value[10];
const MSList *elem;
PayloadType *candidate=NULL;
for (elem=l;elem!=NULL;elem=elem->next){
pt=(PayloadType*)elem->data;
if (strcasecmp(pt->mime_type,refpt->mime_type)==0 && pt->clock_rate==refpt->clock_rate){
candidate=pt;
/*good candidate, check fmtp for H264 */
if (strcasecmp(pt->mime_type,"H264")==0){
if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL){
int mode1=0,mode2=0;
if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){
mode1=atoi(value);
}
if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){
mode2=atoi(value);
}
if (mode1==mode2)
break; /*exact match */
}
}else break;
}
}
return candidate;
}
static MSList *match_payloads(const MSList *local, const MSList *remote){
const MSList *e2;
MSList *res=NULL;
PayloadType *matched;
for(e2=remote;e2!=NULL;e2=e2->next){
PayloadType *p2=(PayloadType*)e2->data;
matched=find_payload_type_best_match(local,p2);
if (matched){
matched=payload_type_clone(matched);
if (p2->recv_fmtp)
payload_type_set_send_fmtp(matched,p2->recv_fmtp);
res=ms_list_append(res,matched);
payload_type_set_number(matched,payload_type_get_number(p2));
}else{
ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate);
}
}
return res;
}
static bool_t only_telephone_event(const MSList *l){
PayloadType *p=(PayloadType*)l->data;
if (strcasecmp(p->mime_type,"telephone-event")!=0){
return FALSE;
}
return TRUE;
}
static void initiate_outgoing(const SalStreamDescription *local_offer,
const SalStreamDescription *remote_answer,
SalStreamDescription *result){
if (remote_answer->port!=0)
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads);
result->proto=local_offer->proto;
result->type=local_offer->type;
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,remote_answer->addr);
result->port=remote_answer->port;
result->bandwidth=remote_answer->bandwidth;
result->ptime=remote_answer->ptime;
}else{
result->port=0;
}
}
static void initiate_incoming(const SalStreamDescription *local_cap,
const SalStreamDescription *remote_offer,
SalStreamDescription *result){
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads);
result->proto=local_cap->proto;
result->type=local_cap->type;
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,local_cap->addr);
result->port=local_cap->port;
result->bandwidth=local_cap->bandwidth;
result->ptime=local_cap->ptime;
}else{
result->port=0;
}
}
/**
* Returns a media description to run the streams with, based on a local offer
* and the returned response (remote).
**/
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
const SalMediaDescription *remote_answer,
SalMediaDescription *result){
int i,j;
const SalStreamDescription *ls,*rs;
for(i=0,j=0;i<local_offer->nstreams;++i){
ms_message("Processing for stream %i",i);
ls=&local_offer->streams[i];
rs=sal_media_description_find_stream(remote_answer,ls->proto,ls->type);
if (rs) {
initiate_outgoing(ls,rs,&result->streams[j]);
++j;
}
else ms_warning("No matching stream for %i",i);
}
result->nstreams=j;
strcpy(result->addr,remote_answer->addr);
return 0;
}
/**
* Returns a media description to run the streams with, based on the local capabilities and
* and the received offer.
* The returned media description is an answer and should be sent to the offerer.
**/
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
const SalMediaDescription *remote_offer,
SalMediaDescription *result){
int i,j;
const SalStreamDescription *ls,*rs;
for(i=0,j=0;i<remote_offer->nstreams;++i){
rs=&remote_offer->streams[i];
ms_message("Processing for stream %i",i);
ls=sal_media_description_find_stream(local_capabilities,rs->proto,rs->type);
if (ls){
initiate_incoming(ls,rs,&result->streams[j]);
++j;
}
}
result->nstreams=j;
strcpy(result->username, local_capabilities->username);
strcpy(result->addr,local_capabilities->addr);
return 0;
}

47
coreapi/offeranswer.h Normal file
View file

@ -0,0 +1,47 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef offeranswer_h
#define offeranswer_h
/**
This header files defines the SDP offer answer API.
It can be used by implementations of SAL directly.
**/
/**
* Returns a media description to run the streams with, based on a local offer
* and the returned response (remote).
**/
int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
const SalMediaDescription *remote_answer,
SalMediaDescription *result);
/**
* Returns a media description to run the streams with, based on the local capabilities and
* and the received offer.
* The returned media description is an answer and should be sent to the offerer.
**/
int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities,
const SalMediaDescription *remote_offer,
SalMediaDescription *result);
#endif

View file

@ -18,26 +18,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphonecore.h"
#include <eXosip2/eXosip.h>
#include <osipparser2/osip_message.h>
#include "private.h"
extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol);
void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, int did, int nid){
void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalOp *op){
LinphoneFriend *fl=linphone_friend_new_with_addr(subscriber);
if (fl==NULL) return ;
fl->in_did=did;
linphone_friend_set_nid(fl,nid);
fl->insub=op;
linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept);
fl->inc_subscribe_pending=TRUE;
lc->subscribers=ms_list_append(lc->subscribers,(void *)fl);
if (lc->vtable.new_unknown_subscriber!=NULL) {
char *subscriber=linphone_address_as_string(fl->uri);
lc->vtable.new_unknown_subscriber(lc,fl,subscriber);
ms_free(subscriber);
char *tmp=linphone_address_as_string(fl->uri);
lc->vtable.new_unknown_subscriber(lc,fl,tmp);
ms_free(tmp);
}
}
@ -45,167 +42,115 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){
linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPDeny);
}
static void __do_notify(void * data, void * user_data){
int *tab=(int*)user_data;
LinphoneFriend *lf=(LinphoneFriend*)data;
linphone_friend_notify(lf,tab[0],tab[1]);
}
void __linphone_core_notify_all_friends(LinphoneCore *lc, int ss, int os){
int tab[2];
tab[0]=ss;
tab[1]=os;
ms_list_for_each2(lc->friends,__do_notify,(void *)tab);
}
void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os){
MSList *elem;
ms_message("Notifying all friends that we are in status %i",os);
__linphone_core_notify_all_friends(lc,EXOSIP_SUBCRSTATE_ACTIVE,os);
for(elem=lc->friends;elem!=NULL;elem=elem->next){
LinphoneFriend *lf=(LinphoneFriend *)elem->data;
if (lf->insub){
linphone_friend_notify(lf,os);
}
}
}
/* check presence state before answering to call; returns TRUE if we can proceed, else answer the appropriate answer
to close the dialog*/
bool_t linphone_core_check_presence(LinphoneCore *lc){
return TRUE;
}
void linphone_subscription_new(LinphoneCore *lc, eXosip_event_t *ev){
void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
LinphoneFriend *lf=NULL;
osip_from_t *from=ev->request->from;
char *tmp;
osip_message_t *msg=NULL;
LinphoneAddress *uri;
osip_from_to_str(ev->request->from,&tmp);
uri=linphone_address_new(tmp);
ms_message("Receiving new subscription from %s.",tmp);
uri=linphone_address_new(from);
linphone_address_clean(uri);
tmp=linphone_address_as_string(uri);
ms_message("Receiving new subscription from %s.",from);
/* check if we answer to this subscription */
if (linphone_find_friend(lc->friends,uri,&lf)!=NULL){
lf->in_did=ev->did;
linphone_friend_set_nid(lf,ev->nid);
eXosip_insubscription_build_answer(ev->tid,202,&msg);
eXosip_insubscription_send_answer(ev->tid,202,msg);
__eXosip_wakeup_event();
lf->insub=op;
lf->inc_subscribe_pending=TRUE;
sal_subscribe_accept(op);
linphone_friend_done(lf); /*this will do all necessary actions */
}else{
/* check if this subscriber is in our black list */
if (linphone_find_friend(lc->subscribers,uri,&lf)){
if (lf->pol==LinphoneSPDeny){
ms_message("Rejecting %s because we already rejected it once.",from);
eXosip_insubscription_send_answer(ev->tid,401,NULL);
sal_subscribe_decline(op);
}
else {
/* else it is in wait for approval state, because otherwise it is in the friend list.*/
ms_message("New subscriber found in friend list, in %s state.",__policy_enum_to_str(lf->pol));
}
}else {
eXosip_insubscription_build_answer(ev->tid,202,&msg);
eXosip_insubscription_send_answer(ev->tid,202,msg);
linphone_core_add_subscriber(lc,tmp,ev->did,ev->nid);
sal_subscribe_accept(op);
linphone_core_add_subscriber(lc,tmp,op);
}
}
osip_free(tmp);
linphone_address_destroy(uri);
ms_free(tmp);
}
void linphone_notify_recv(LinphoneCore *lc, eXosip_event_t *ev)
{
const char *status=_("Gone");
const char *img="sip-closed.png";
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus sal_status){
char *tmp;
LinphoneFriend *lf;
LinphoneAddress *friend=NULL;
osip_from_t *from=NULL;
osip_body_t *body=NULL;
LinphoneOnlineStatus estatus=LINPHONE_STATUS_UNKNOWN;
ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid);
if (ev->request!=NULL){
from=ev->request->from;
osip_message_get_body(ev->request,0,&body);
if (body==NULL){
ms_error("No body in NOTIFY");
return;
}
if (strstr(body->body,"pending")!=NULL){
status=_("Waiting for Approval");
img="sip-wfa.png";
estatus=LINPHONE_STATUS_PENDING;
}else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) {
status=_("Online");
img="sip-online.png";
estatus=LINPHONE_STATUS_ONLINE;
}else if (strstr(body->body,"busy")!=NULL){
status=_("Busy");
img="sip-busy.png";
estatus=LINPHONE_STATUS_BUSY;
}else if (strstr(body->body,"berightback")!=NULL
|| strstr(body->body,"in-transit")!=NULL ){
status=_("Be Right Back");
img="sip-bifm.png";
estatus=LINPHONE_STATUS_BERIGHTBACK;
}else if (strstr(body->body,"away")!=NULL){
status=_("Away");
img="sip-away.png";
estatus=LINPHONE_STATUS_AWAY;
}else if (strstr(body->body,"onthephone")!=NULL
|| strstr(body->body,"on-the-phone")!=NULL){
status=_("On The Phone");
img="sip-otp.png";
estatus=LINPHONE_STATUS_ONTHEPHONE;
}else if (strstr(body->body,"outtolunch")!=NULL
|| strstr(body->body,"meal")!=NULL){
status=_("Out To Lunch");
img="sip-otl.png";
estatus=LINPHONE_STATUS_OUTTOLUNCH;
}else if (strstr(body->body,"closed")!=NULL){
status=_("Closed");
img="sip-away.png";
estatus=LINPHONE_STATUS_CLOSED;
}else{
status=_("Gone");
img="sip-closed.png";
LinphoneOnlineStatus estatus=LINPHONE_STATUS_OFFLINE;
switch(sal_status){
case SalPresenceOffline:
estatus=LINPHONE_STATUS_OFFLINE;
}
ms_message("We are notified that sip:%s@%s has online status %s",from->url->username,from->url->host,status);
break;
case SalPresenceOnline:
estatus=LINPHONE_STATUS_ONLINE;
break;
case SalPresenceBusy:
estatus=LINPHONE_STATUS_BUSY;
break;
case SalPresenceBerightback:
estatus=LINPHONE_STATUS_AWAY;
break;
case SalPresenceAway:
estatus=LINPHONE_STATUS_AWAY;
break;
case SalPresenceOnthephone:
estatus=LINPHONE_STATUS_ONTHEPHONE;
break;
case SalPresenceOuttolunch:
estatus=LINPHONE_STATUS_OUTTOLUNCH;
break;
case SalPresenceDonotdisturb:
estatus=LINPHONE_STATUS_BUSY;
break;
case SalPresenceMoved:
case SalPresenceAltService:
estatus=LINPHONE_STATUS_AWAY;
break;
}
lf=linphone_find_friend_by_sid(lc->friends,ev->sid);
lf=linphone_find_friend_by_out_subscribe(lc->friends,op);
if (lf!=NULL){
friend=lf->uri;
tmp=linphone_address_as_string(friend);
lf->status=estatus;
lc->vtable.notify_recv(lc,(LinphoneFriend*)lf,tmp,status,img);
lf->subscribe_active=TRUE;
lc->vtable.notify_recv(lc,(LinphoneFriend*)lf);
ms_free(tmp);
if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) {
lf->sid=-1;
lf->out_did=-1;
ms_message("Outgoing subscription terminated by remote.");
}
}else{
ms_message("But this person is not part of our friend list, so we don't care.");
}
if (ss==SalSubscribeTerminated){
sal_op_release(op);
if (lf){
lf->outsub=NULL;
lf->subscribe_active=FALSE;
}
}
}
void linphone_subscription_answered(LinphoneCore *lc, eXosip_event_t *ev){
void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){
LinphoneFriend *lf;
osip_from_t *from=ev->response->to;
char *tmp;
osip_from_to_str(from,&tmp);
LinphoneAddress *uri=linphone_address_new(tmp);
linphone_find_friend(lc->friends,uri,&lf);
lf=linphone_find_friend_by_inc_subscribe(lc->friends,op);
sal_op_release(op);
if (lf!=NULL){
lf->out_did=ev->did;
linphone_friend_set_sid(lf,ev->sid);
lf->insub=NULL;
}else{
ms_warning("Receiving answer for unknown subscribe sip:%s@%s", from->url->username,from->url->host);
}
ms_free(tmp);
}
void linphone_subscription_closed(LinphoneCore *lc,eXosip_event_t *ev){
LinphoneFriend *lf;
osip_from_t *from=ev->request->from;
lf=linphone_find_friend_by_nid(lc->friends,ev->nid);
if (lf!=NULL){
lf->in_did=-1;
linphone_friend_set_nid(lf,-1);
}else{
ms_warning("Receiving unsuscribe for unknown in-subscribtion from sip:%s@%s", from->url->username, from->url->host);
ms_warning("Receiving unsuscribe for unknown in-subscribtion from %s", sal_op_get_from(op));
}
}

View file

@ -26,7 +26,7 @@
#define _PRIVATE_H
#include "linphonecore.h"
#include <eXosip2/eXosip.h>
#include "sal.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -54,23 +54,9 @@
#endif
#endif
typedef struct _StreamParams
{
int initialized;
int line;
int localport;
int remoteport;
int remotertcpport;
int pt;
char *relay_session_id;
int natd_port;
char remoteaddr[LINPHONE_HOSTNAME_SIZE];
char natd_addr[LINPHONE_HOSTNAME_SIZE];
} StreamParams;
typedef enum _LCState{
LCStateInit,
LCStatePreEstablishing,
LCStateRinging,
LCStateAVRunning
}LCState;
@ -79,25 +65,23 @@ typedef enum _LCState{
typedef struct _LinphoneCall
{
struct _LinphoneCore *core;
StreamParams audio_params;
StreamParams video_params;
SalMediaDescription *localdesc;
SalMediaDescription *resultdesc;
LinphoneCallDir dir;
struct _RtpProfile *profile; /*points to the local_profile or to the remote "guessed" profile*/
struct _RtpProfile *audio_profile;
struct _RtpProfile *video_profile;
struct _LinphoneCallLog *log;
int cid; /*call id */
int did; /*dialog id */
int tid; /*last transaction id*/
SalOp *op;
SalOp *ping_op;
char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */
struct _sdp_context *sdpctx;
time_t start_time; /*time at which the call was initiated*/
time_t media_start_time; /*time at which it was accepted, media streams established*/
LCState state;
bool_t auth_pending;
bool_t supports_session_timers;
bool_t media_pending;
} LinphoneCall;
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to);
LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, eXosip_event_t *ev);
LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op);
#define linphone_call_set_state(lcall,st) (lcall)->state=(st)
void linphone_call_destroy(struct _LinphoneCall *obj);
@ -107,7 +91,7 @@ void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call);
void linphone_call_log_destroy(LinphoneCallLog *cl);
void linphone_core_init_media_streams(LinphoneCore *lc);
void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call);
void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos);
@ -117,27 +101,26 @@ void linphone_core_refresh_subscribes(LinphoneCore *lc);
int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os);
int linphone_online_status_to_eXosip(LinphoneOnlineStatus os);
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os);
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op);
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op);
void linphone_friend_set_sid(LinphoneFriend *lf, int sid);
void linphone_friend_set_nid(LinphoneFriend *lf, int nid);
void linphone_friend_notify(LinphoneFriend *lf, int ss, LinphoneOnlineStatus os);
int set_lock_file();
int get_lock_file();
int remove_lock_file();
int do_registration(LinphoneCore *lc, bool_t doit);
void check_for_registration(LinphoneCore *lc);
char *int2str(int number);
int from_2char_without_params(osip_from_t *from,char **str);
void check_sound_device(LinphoneCore *lc);
void linphone_core_setup_local_rtp_profile(LinphoneCore *lc);
void linphone_core_verify_codecs(LinphoneCore *lc);
void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result);
bool_t host_has_ipv6_network();
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret);
static inline int get_min_bandwidth(int dbw, int ubw){
if (dbw<0) return ubw;
if (ubw<0) return dbw;
if (dbw<=0) return ubw;
if (ubw<=0) return dbw;
return MIN(dbw,ubw);
}
@ -157,24 +140,18 @@ static inline void set_string(char **dest, const char *src){
}
#define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0
bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyConfig *obj, osip_message_t *orig_request, osip_message_t *last_answer);
void linphone_process_authentication(LinphoneCore* lc, eXosip_event_t *ev);
void linphone_authentication_ok(LinphoneCore *lc, eXosip_event_t *ev);
void linphone_subscription_new(LinphoneCore *lc, eXosip_event_t *ev);
void linphone_notify_recv(LinphoneCore *lc,eXosip_event_t *ev);
LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid);
void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, int code, eXosip_event_t *ev);
void linphone_subscription_answered(LinphoneCore *lc, eXosip_event_t *ev);
void linphone_subscription_closed(LinphoneCore *lc, eXosip_event_t *ev);
SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os);
void linphone_process_authentication(LinphoneCore* lc, SalOp *op);
void linphone_authentication_ok(LinphoneCore *lc, SalOp *op);
void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from);
void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus status);
void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op);
void linphone_call_init_media_params(LinphoneCall *call);
void linphone_set_sdp(osip_message_t *sip, const char *sdp);
void linphone_subscription_answered(LinphoneCore *lc, SalOp *op);
void linphone_subscription_closed(LinphoneCore *lc, SalOp *op);
MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *fri, LinphoneFriend **lf);
LinphoneFriend *linphone_find_friend_by_nid(MSList *l, int nid);
LinphoneFriend *linphone_find_friend_by_sid(MSList *l, int sid);
void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCore *lc, const PayloadType *pt);
@ -194,4 +171,231 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg);
void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
const char * linphone_core_get_route(LinphoneCore *lc);
void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose);
void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses);
void linphone_core_stop_waiting(LinphoneCore *lc);
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
extern SalCallbacks linphone_sal_callbacks;
struct _LinphoneProxyConfig
{
struct _LinphoneCore *lc;
char *reg_proxy;
char *reg_identity;
char *reg_route;
char *realm;
int expires;
int reg_time;
SalOp *op;
char *type;
struct _SipSetupContext *ssctx;
int auth_failures;
char *dial_prefix;
bool_t commit;
bool_t reg_sendregister;
bool_t registered;
bool_t publish;
bool_t dial_escape_plus;
void* user_data;
};
struct _LinphoneAuthInfo
{
char *username;
char *realm;
char *userid;
char *passwd;
char *ha1;
int usecount;
bool_t works;
};
struct _LinphoneChatRoom{
struct _LinphoneCore *lc;
char *peer;
char *route;
LinphoneAddress *peer_url;
void * user_data;
};
struct _LinphoneFriend{
LinphoneAddress *uri;
SalOp *insub;
SalOp *outsub;
LinphoneSubscribePolicy pol;
LinphoneOnlineStatus status;
struct _LinphoneCore *lc;
BuddyInfo *info;
char *refkey;
bool_t subscribe;
bool_t subscribe_active;
bool_t inc_subscribe_pending;
};
typedef struct sip_config
{
char *contact;
char *guessed_contact;
int sip_port;
MSList *proxies;
MSList *deleted_proxies;
int inc_timeout; /*timeout after an un-answered incoming call is rejected*/
bool_t use_info;
bool_t use_rfc2833; /*force RFC2833 to be sent*/
bool_t guess_hostname;
bool_t loopback_only;
bool_t ipv6_enabled;
bool_t sdp_200_ack;
bool_t only_one_codec; /*in SDP answers*/
bool_t register_only_when_network_is_up;
bool_t ping_with_options;
bool_t auto_net_state_mon;
} sip_config_t;
typedef struct rtp_config
{
int audio_rtp_port;
int video_rtp_port;
int audio_jitt_comp; /*jitter compensation*/
int video_jitt_comp; /*jitter compensation*/
int nortp_timeout;
}rtp_config_t;
typedef struct net_config
{
char *nat_address;
char *stun_server;
char *relay;
int download_bw;
int upload_bw;
int firewall_policy;
int mtu;
int down_ptime;
bool_t nat_sdp_only;
}net_config_t;
typedef struct sound_config
{
struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */
struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */
struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */
const char **cards;
int latency; /* latency in samples of the current used sound device */
char rec_lev;
char play_lev;
char ring_lev;
char soft_play_lev;
char source;
char *local_ring;
char *remote_ring;
bool_t ec;
bool_t ea;
bool_t agc;
} sound_config_t;
typedef struct codecs_config
{
MSList *audio_codecs; /* list of audio codecs in order of preference*/
MSList *video_codecs; /* for later use*/
}codecs_config_t;
typedef struct video_config{
struct _MSWebCam *device;
const char **cams;
MSVideoSize vsize;
bool_t capture;
bool_t show_local;
bool_t display;
bool_t selfview; /*during calls*/
}video_config_t;
typedef struct ui_config
{
int is_daemon;
int is_applet;
unsigned int timer_id; /* the timer id for registration */
}ui_config_t;
typedef struct autoreplier_config
{
int enabled;
int after_seconds; /* accept the call after x seconds*/
int max_users; /* maximum number of user that can call simultaneously */
int max_rec_time; /* the max time of incoming voice recorded */
int max_rec_msg; /* maximum number of recorded messages */
const char *message; /* the path of the file to be played */
}autoreplier_config_t;
struct _LinphoneCore
{
LinphoneCoreVTable vtable;
Sal *sal;
struct _LpConfig *config;
net_config_t net_conf;
sip_config_t sip_conf;
rtp_config_t rtp_conf;
sound_config_t sound_conf;
video_config_t video_conf;
codecs_config_t codecs_conf;
ui_config_t ui_conf;
autoreplier_config_t autoreplier_conf;
LinphoneProxyConfig *default_proxy;
MSList *friends;
MSList *auth_info;
struct _RingStream *ringstream;
LCCallbackObj preview_finished_cb;
struct _LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/
MSList *queued_calls; /* used by the autoreplier */
MSList *call_logs;
MSList *chatrooms;
int max_call_logs;
int missed_calls;
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
struct _VideoStream *previewstream;
RtpTransport *a_rtp,*a_rtcp;
MSList *bl_reqs;
MSList *subscribers; /* unknown subscribers */
int minutes_away;
LinphoneOnlineStatus presence_mode;
LinphoneOnlineStatus prev_mode;
char *alt_contact;
void *data;
char *play_file;
char *rec_file;
time_t prevtime;
int dw_audio_bw;
int up_audio_bw;
int dw_video_bw;
int up_video_bw;
int audio_bw;
gstate_t gstate_power;
gstate_t gstate_reg;
gstate_t gstate_call;
LinphoneWaitingCallback wait_cb;
void *wait_ctx;
bool_t use_files;
bool_t apply_nat_settings;
bool_t ready;
bool_t bl_refresh;
bool_t preview_finished;
bool_t auto_net_state_mon;
bool_t network_reachable;
};
#endif /* _PRIVATE_H */

View file

@ -20,8 +20,6 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
#include "linphonecore.h"
#include "sipsetup.h"
#include <eXosip2/eXosip.h>
#include <osipparser2/osip_message.h>
#include "lpconfig.h"
#include "private.h"
@ -40,7 +38,6 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
void linphone_proxy_config_init(LinphoneProxyConfig *obj){
memset(obj,0,sizeof(LinphoneProxyConfig));
obj->rid=-1;
obj->expires=3600;
}
@ -72,8 +69,8 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){
if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx);
if (obj->realm!=NULL) ms_free(obj->realm);
if (obj->type!=NULL) ms_free(obj->type);
if (obj->contact_addr!=NULL) ms_free(obj->contact_addr);
if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix);
if (obj->op) sal_op_release(obj->op);
}
/**
@ -83,79 +80,6 @@ bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){
return obj->registered;
}
void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port){
if (cfg->registered){
*ip=cfg->contact_addr;
*port=cfg->contact_port;
}else{
*ip=NULL;
*port=0;
}
}
static void update_contact(LinphoneProxyConfig *cfg, const char *ip, const char *port){
if (cfg->contact_addr){
ms_free(cfg->contact_addr);
}
cfg->contact_addr=ms_strdup(ip);
if (port!=NULL)
cfg->contact_port=atoi(port);
else cfg->contact_port=5060;
}
bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyConfig *obj, osip_message_t *orig_request, osip_message_t *last_answer){
osip_message_t *msg;
const char *rport,*received;
osip_via_t *via=NULL;
osip_generic_param_t *param=NULL;
osip_contact_t *ctt=NULL;
osip_message_get_via(last_answer,0,&via);
if (!via) return FALSE;
osip_via_param_get_byname(via,"rport",&param);
if (param) rport=param->gvalue;
else return FALSE;
param=NULL;
osip_via_param_get_byname(via,"received",&param);
if (param) received=param->gvalue;
else return FALSE;
osip_message_get_contact(orig_request,0,&ctt);
if (strcmp(ctt->url->host,received)==0){
/*ip address matches, check ports*/
const char *contact_port=ctt->url->port;
const char *via_rport=rport;
if (via_rport==NULL || strlen(via_rport)>0)
via_rport="5060";
if (contact_port==NULL || strlen(contact_port)>0)
contact_port="5060";
if (strcmp(contact_port,via_rport)==0){
ms_message("Register has up to date contact, doing nothing.");
return FALSE;
}else ms_message("ports do not match, need to update the register (%s <> %s)", contact_port,via_rport);
}
eXosip_lock();
msg=NULL;
eXosip_register_build_register(obj->rid,obj->expires,&msg);
if (msg==NULL){
eXosip_unlock();
ms_warning("Fail to create a contact updated register.");
return FALSE;
}
osip_message_get_contact(msg,0,&ctt);
if (ctt->url->host!=NULL){
osip_free(ctt->url->host);
}
ctt->url->host=osip_strdup(received);
if (ctt->url->port!=NULL){
osip_free(ctt->url->port);
}
ctt->url->port=osip_strdup(rport);
eXosip_register_send_register(obj->rid,msg);
eXosip_unlock();
update_contact(obj,received,rport);
ms_message("Resending new register with updated contact %s:%s",received,rport);
return TRUE;
}
/**
* Sets the proxy address
*
@ -165,19 +89,29 @@ bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyCo
* - hostnames : sip:sip.example.net
**/
int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){
int err;
osip_from_t *url;
LinphoneAddress *addr;
char *try=NULL;
if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy);
obj->reg_proxy=NULL;
if (server_addr!=NULL && strlen(server_addr)>0){
osip_from_init(&url);
err=osip_from_parse(url,server_addr);
if (err==0 && url->url->host!=NULL){
obj->reg_proxy=ms_strdup(server_addr);
addr=linphone_address_new(server_addr);
if (!addr){
/*try to prepend 'sip:' */
if (strstr(server_addr,"sip:")==NULL){
try=ms_strdup_printf("sip:%s",server_addr);
addr=linphone_address_new(try);
ms_free(try);
}
}
if (addr){
obj->reg_proxy=linphone_address_as_string_uri_only(addr);
linphone_address_destroy(addr);
}else{
ms_warning("Could not parse %s",server_addr);
return -1;
}
osip_from_free(url);
}
return 0;
}
@ -191,30 +125,30 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *
* The REGISTER messages will have from and to set to this identity.
*
**/
void linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity){
int err=0;
osip_from_t *url=NULL;
int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity){
LinphoneAddress *addr;
if (identity!=NULL && strlen(identity)>0){
osip_from_init(&url);
err=osip_from_parse(url,identity);
if (err<0 || url->url->host==NULL || url->url->username==NULL){
ms_warning("Could not parse %s",identity);
osip_from_free(url);
return;
addr=linphone_address_new(identity);
if (!addr || linphone_address_get_username(addr)==NULL){
ms_warning("Invalid sip identity: %s",identity);
if (addr)
linphone_address_destroy(addr);
return -1;
}else{
if (obj->reg_identity!=NULL) {
ms_free(obj->reg_identity);
obj->reg_identity=NULL;
}
obj->reg_identity=ms_strdup(identity);
if (obj->realm){
ms_free(obj->realm);
}
obj->realm=ms_strdup(linphone_address_get_domain(addr));
linphone_address_destroy(addr);
return 0;
}
} else err=-2;
if (obj->reg_identity!=NULL) {
ms_free(obj->reg_identity);
obj->reg_identity=NULL;
}
if (err==-2) obj->reg_identity=NULL;
else {
obj->reg_identity=ms_strdup(identity);
if (obj->realm)
ms_free(obj->realm);
obj->realm=ms_strdup(url->url->host);
}
if (url) osip_from_free(url);
return -1;
}
const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){
@ -226,37 +160,14 @@ const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){
* When a route is set, all outgoing calls will go to the route's destination if this proxy
* is the default one (see linphone_core_set_default_proxy() ).
**/
void linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route)
int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route)
{
int err;
osip_uri_param_t *lr_param=NULL;
osip_route_t *rt=NULL;
char *tmproute=NULL;
if (route!=NULL && strlen(route)>0){
osip_route_init(&rt);
err=osip_route_parse(rt,route);
if (err<0){
ms_warning("Could not parse %s",route);
osip_route_free(rt);
return ;
}
if (obj->reg_route!=NULL) {
ms_free(obj->reg_route);
obj->reg_route=NULL;
}
/* check if the lr parameter is set , if not add it */
osip_uri_uparam_get_byname(rt->url, "lr", &lr_param);
if (lr_param==NULL){
osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL);
osip_route_to_str(rt,&tmproute);
obj->reg_route=ms_strdup(tmproute);
osip_free(tmproute);
}else obj->reg_route=ms_strdup(route);
}else{
if (obj->reg_route!=NULL) ms_free(obj->reg_route);
if (obj->reg_route!=NULL){
ms_free(obj->reg_route);
obj->reg_route=NULL;
}
obj->reg_route=ms_strdup(route);
return 0;
}
bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *obj){
@ -304,15 +215,10 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){
* linphone_proxy_config_done() to commit the changes.
**/
void linphone_proxy_config_edit(LinphoneProxyConfig *obj){
obj->auth_failures=0;
if (obj->reg_sendregister){
/* unregister */
if (obj->registered) {
osip_message_t *msg;
eXosip_lock();
eXosip_register_build_register(obj->rid,0,&msg);
eXosip_register_send_register(obj->rid,msg);
eXosip_unlock();
sal_unregister(obj->op);
obj->registered=FALSE;
}
}
@ -329,13 +235,11 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
if (obj->reg_identity!=NULL) id_str=obj->reg_identity;
else id_str=linphone_core_get_primary_contact(obj->lc);
if (obj->reg_sendregister){
char *ct=NULL;
osip_message_t *msg=NULL;
eXosip_lock();
obj->rid=eXosip_register_build_initial_register(id_str,obj->reg_proxy,NULL,obj->expires,&msg);
eXosip_register_send_register(obj->rid,msg);
eXosip_unlock();
if (ct!=NULL) osip_free(ct);
if (obj->op)
sal_op_release(obj->op);
obj->op=sal_op_new(obj->lc->sal);
sal_op_set_user_pointer(obj->op,obj);
sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires);
}
}
@ -350,7 +254,7 @@ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char
ms_free(cfg->dial_prefix);
cfg->dial_prefix=NULL;
}
if (prefix) cfg->dial_prefix=ms_strdup(prefix);
if (prefix && prefix[0]!='\0') cfg->dial_prefix=ms_strdup(prefix);
}
/**
@ -484,172 +388,62 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm
}
int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy,
LinphoneOnlineStatus presence_mode)
{
osip_message_t *pub;
int i;
const char *from=NULL;
char buf[5000];
if (proxy->publish==FALSE) return 0;
if (proxy!=NULL) {
from=linphone_proxy_config_get_identity(proxy);
}
if (from==NULL) from=linphone_core_get_primary_contact(proxy->lc);
if (presence_mode==LINPHONE_STATUS_ONLINE)
{
snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>online</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==LINPHONE_STATUS_BUSY
||presence_mode==LINPHONE_STATUS_NOT_DISTURB)
{
snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>busy</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>busy</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==LINPHONE_STATUS_BERIGHTBACK)
{
snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>in-transit</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>be right back</note>\n\
</tuple>\n\
</presence>",
from,from);
}
else if (presence_mode==LINPHONE_STATUS_AWAY
||presence_mode==LINPHONE_STATUS_MOVED
||presence_mode==LINPHONE_STATUS_ALT_SERVICE)
{
snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>away</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>away</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==LINPHONE_STATUS_ONTHEPHONE)
{
snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>on-the-phone</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>on the phone</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==LINPHONE_STATUS_OUTTOLUNCH)
{
snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>meal</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>out to lunch</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==LINPHONE_STATUS_OFFLINE)
{
/* */
snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n%s",
from,
"<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>closed</basic>\n\
<es:activities>\n\
<es:activity>permanent-absence</e:activity>\n\
</es:activities>\n\
</status>\n\
</tuple>\n\
\n</presence>\n");
}
i = eXosip_build_publish(&pub, (char *)from, (char *)from, NULL, "presence", "1800", "application/pidf+xml", buf);
if (i<0)
{
ms_message("Failed to build publish request.");
return -1;
}
eXosip_lock();
i = eXosip_publish(pub, from); /* should update the sip-if-match parameter
from sip-etag from last 200ok of PUBLISH */
eXosip_unlock();
if (i<0)
{
ms_message("Failed to send publish request.");
return -1;
}
return 0;
LinphoneOnlineStatus presence_mode){
int err;
SalOp *op=sal_op_new(proxy->lc->sal);
err=sal_publish(op,linphone_proxy_config_get_identity(proxy),
linphone_proxy_config_get_identity(proxy),linphone_online_status_to_sal(presence_mode));
sal_op_release(op);
return err;
}
/**
* Returns the route set for this proxy configuration.
**/
const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj){
return obj->reg_route;
}
/**
* Returns the SIP identity that belongs to this proxy configuration.
*
* The SIP identity is a SIP address (Display Name <sip:username@domain> )
**/
const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj){
return obj->reg_identity;
}
/**
* Returns TRUE if PUBLISH request is enabled for this proxy.
**/
bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj){
return obj->publish;
}
/**
* Returns the proxy's SIP address.
**/
const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj){
return obj->reg_proxy;
}
/**
* Returns the duration of registration.
**/
int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj){
return obj->expires;
}
/**
* Returns TRUE if registration to the proxy is enabled.
**/
bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj){
return obj->reg_sendregister;
}
struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj){
return obj->lc;
}
/**
* Add a proxy configuration.
@ -657,13 +451,15 @@ entity=\"%s\">\n%s",
**/
int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
if (!linphone_proxy_config_check(lc,cfg)) return -1;
if (ms_list_find(lc->sip_conf.proxies,cfg)!=NULL){
ms_warning("ProxyConfig already entered, ignored.");
return 0;
}
lc->sip_conf.proxies=ms_list_append(lc->sip_conf.proxies,(void *)cfg);
linphone_proxy_config_apply(cfg,lc);
return 0;
}
extern void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, LinphoneProxyConfig *cfg);
/**
* Removes a proxy configuration.
*
@ -671,7 +467,6 @@ extern void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, Linphone
* on a deleted list. For that reason, a removed proxy does NOT need to be freed.
**/
void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
MSList *elem;
lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,(void *)cfg);
/* add to the list of destroyed proxies, so that the possible unREGISTER request can succeed authentication */
lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,(void *)cfg);
@ -680,11 +475,6 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf
if (lc->default_proxy==cfg){
lc->default_proxy=NULL;
}
/* invalidate all references to this proxy in our friend list */
for (elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){
linphone_friend_check_for_removed_proxy((LinphoneFriend*)elem->data,cfg);
}
}
/**
* Erase all proxies from config.
@ -735,23 +525,6 @@ int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **conf
return pos;
}
static int rid_compare(const void *pcfg,const void *prid){
const LinphoneProxyConfig *cfg=(const LinphoneProxyConfig*)pcfg;
const int *rid=(const int*)prid;
ms_message("cfg= %s, cfg->rid=%i, rid=%i",cfg->reg_proxy, cfg->rid, *rid);
return cfg->rid-(*rid);
}
LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid){
MSList *elem=ms_list_find_custom(lc->sip_conf.proxies,rid_compare, &rid);
if (elem==NULL){
ms_message("linphone_core_get_proxy_config_from_rid: searching in deleted proxies...");
elem=ms_list_find_custom(lc->sip_conf.deleted_proxies,rid_compare, &rid);
}
if (elem==NULL) return NULL;
else return (LinphoneProxyConfig*)elem->data;
}
/**
* Returns an unmodifiable list of entered proxy configurations.
**/
@ -759,47 +532,6 @@ const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc){
return lc->sip_conf.proxies;
}
void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, int code, eXosip_event_t *ev){
if (code==403) {
LinphoneProxyConfig *cfg=linphone_core_get_proxy_config_from_rid(lc, ev->rid);
if (cfg){
cfg->auth_failures++;
/*restart a new register so that the user gets a chance to be prompted for a password*/
if (cfg->auth_failures==1){
linphone_proxy_config_register(cfg);
}
}
} else {
//unknown error (possibly timeout)
char *prx_realm=NULL,*www_realm=NULL;
osip_proxy_authenticate_t *prx_auth;
osip_www_authenticate_t *www_auth;
osip_message_t *req=ev->request;
char *username;
username=osip_uri_get_username(req->from->url);
prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&req->proxy_authenticates,0);
www_auth=(osip_proxy_authenticate_t*)osip_list_get(&req->www_authenticates,0);
if (prx_auth!=NULL)
prx_realm=osip_proxy_authenticate_get_realm(prx_auth);
if (www_auth!=NULL)
www_realm=osip_www_authenticate_get_realm(www_auth);
if (prx_realm==NULL && www_realm==NULL){
ms_warning("No realm in the client request.");
return;
}
LinphoneAuthInfo *as=NULL;
/* see if we already have this auth information , not to ask it everytime to the user */
if (prx_realm!=NULL)
as=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,prx_realm,username);
if (www_realm!=NULL)
as=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,www_realm,username);
if (as) as->first_time=TRUE;
}
}
void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *obj, int index)
{
char key[50];
@ -1016,5 +748,13 @@ void linphone_account_creator_destroy(LinphoneAccountCreator *obj){
}
}
void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud) {
cr->user_data=ud;
}
void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) {
return cr->user_data;
}

172
coreapi/sal.c Normal file
View file

@ -0,0 +1,172 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
This header files defines the Signaling Abstraction Layer.
The purpose of this layer is too allow experiment different call signaling
protocols and implementations under linphone, for example SIP, JINGLE...
**/
#include "sal.h"
SalMediaDescription *sal_media_description_new(){
SalMediaDescription *md=ms_new0(SalMediaDescription,1);
md->refcount=1;
return md;
}
static void sal_media_description_destroy(SalMediaDescription *md){
int i;
for(i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++){
ms_list_for_each(md->streams[i].payloads,(void (*)(void *))payload_type_destroy);
ms_list_free(md->streams[i].payloads);
md->streams[i].payloads=NULL;
}
ms_free(md);
}
void sal_media_description_ref(SalMediaDescription *md){
md->refcount++;
}
void sal_media_description_unref(SalMediaDescription *md){
md->refcount--;
if (md->refcount==0){
sal_media_description_destroy (md);
}
}
const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md,
SalMediaProto proto, SalStreamType type){
int i;
for(i=0;i<md->nstreams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (ss->proto==proto && ss->type==type) return ss;
}
return NULL;
}
bool_t sal_media_description_empty(SalMediaDescription *md){
int i;
for(i=0;i<md->nstreams;++i){
SalStreamDescription *ss=&md->streams[i];
if (ss->port!=0) return FALSE;
}
return TRUE;
}
static void assign_string(char **str, const char *arg){
if (*str){
ms_free(*str);
*str=NULL;
}
if (arg)
*str=ms_strdup(arg);
}
void sal_op_set_contact(SalOp *op, const char *contact){
assign_string(&((SalOpBase*)op)->contact,contact);
}
void sal_op_set_route(SalOp *op, const char *route){
assign_string(&((SalOpBase*)op)->route,route);
}
void sal_op_set_from(SalOp *op, const char *from){
assign_string(&((SalOpBase*)op)->from,from);
}
void sal_op_set_to(SalOp *op, const char *to){
assign_string(&((SalOpBase*)op)->to,to);
}
void sal_op_set_user_pointer(SalOp *op, void *up){
((SalOpBase*)op)->user_pointer=up;
}
Sal *sal_op_get_sal(const SalOp *op){
return ((SalOpBase*)op)->root;
}
const char *sal_op_get_from(const SalOp *op){
return ((SalOpBase*)op)->from;
}
const char *sal_op_get_to(const SalOp *op){
return ((SalOpBase*)op)->to;
}
const char *sal_op_get_contact(const SalOp *op){
return ((SalOpBase*)op)->contact;
}
const char *sal_op_get_route(const SalOp *op){
return ((SalOpBase*)op)->route;
}
void *sal_op_get_user_pointer(const SalOp *op){
return ((SalOpBase*)op)->user_pointer;
}
const char *sal_op_get_proxy(const SalOp *op){
return ((SalOpBase*)op)->route;
}
const char *sal_op_get_network_origin(const SalOp *op){
return ((SalOpBase*)op)->origin;
}
void __sal_op_init(SalOp *b, Sal *sal){
memset(b,0,sizeof(SalOpBase));
((SalOpBase*)b)->root=sal;
}
void __sal_op_set_network_origin(SalOp *op, const char *origin){
assign_string(&((SalOpBase*)op)->origin,origin);
}
void __sal_op_free(SalOp *op){
SalOpBase *b=(SalOpBase *)op;
if (b->from) {
ms_free(b->from);
b->from=NULL;
}
if (b->to) {
ms_free(b->to);
b->to=NULL;
}
if (b->route) {
ms_free(b->route);
b->route=NULL;
}
if (b->contact) {
ms_free(b->contact);
b->contact=NULL;
}
if (b->origin){
ms_free(b->origin);
b->origin=NULL;
}
if (b->local_media)
sal_media_description_unref(b->local_media);
if (b->remote_media)
sal_media_description_unref(b->remote_media);
ms_free(op);
}

297
coreapi/sal.h Normal file
View file

@ -0,0 +1,297 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
This header files defines the Signaling Abstraction Layer.
The purpose of this layer is too allow experiment different call signaling
protocols and implementations under linphone, for example SIP, JINGLE...
**/
#ifndef sal_h
#define sal_h
#include "mediastreamer2/mscommon.h"
struct Sal;
typedef struct Sal Sal;
struct SalOp;
typedef struct SalOp SalOp;
struct SalAddress;
typedef struct SalAddress SalAddress;
/* Address manipulation API*/
SalAddress * sal_address_new(const char *uri);
SalAddress * sal_address_clone(const SalAddress *addr);
const char *sal_address_get_scheme(const SalAddress *addr);
const char *sal_address_get_display_name(const SalAddress* addr);
const char *sal_address_get_username(const SalAddress *addr);
const char *sal_address_get_domain(const SalAddress *addr);
void sal_address_set_display_name(SalAddress *addr, const char *display_name);
void sal_address_set_username(SalAddress *addr, const char *username);
void sal_address_set_domain(SalAddress *addr, const char *host);
void sal_address_set_port(SalAddress *addr, const char *port);
void sal_address_set_port_int(SalAddress *uri, int port);
void sal_address_clean(SalAddress *addr);
char *sal_address_as_string(const SalAddress *u);
char *sal_address_as_string_uri_only(const SalAddress *u);
void sal_address_destroy(SalAddress *u);
Sal * sal_init();
void sal_uninit(Sal* sal);
void sal_set_user_pointer(Sal *sal, void *user_data);
void *sal_get_user_pointer(const Sal *sal);
typedef enum {
SalTransportDatagram,
SalTransportStream
}SalTransport;
typedef enum {
SalAudio,
SalVideo,
SalOther
} SalStreamType;
typedef enum{
SalProtoUnknown,
SalProtoRtpAvp,
SalProtoRtpSavp
}SalMediaProto;
typedef struct SalEndpointCandidate{
char addr[64];
int port;
}SalEndpointCandidate;
#define SAL_ENDPOINT_CANDIDATE_MAX 2
typedef struct SalStreamDescription{
SalMediaProto proto;
SalStreamType type;
char addr[64];
int port;
MSList *payloads; //<list of PayloadType
int bandwidth;
int ptime;
SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX];
} SalStreamDescription;
#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4
typedef struct SalMediaDescription{
int refcount;
char addr[64];
char username[64];
int nstreams;
SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS];
} SalMediaDescription;
SalMediaDescription *sal_media_description_new();
void sal_media_description_ref(SalMediaDescription *md);
void sal_media_description_unref(SalMediaDescription *md);
bool_t sal_media_description_empty(SalMediaDescription *md);
const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md,
SalMediaProto proto, SalStreamType type);
/*this structure must be at the first byte of the SalOp structure defined by implementors*/
typedef struct SalOpBase{
Sal *root;
char *route; /*or request-uri for REGISTER*/
char *contact;
char *from;
char *to;
char *origin;
SalMediaDescription *local_media;
SalMediaDescription *remote_media;
void *user_pointer;
} SalOpBase;
typedef enum SalError{
SalErrorNoResponse,
SalErrorProtocol,
SalErrorFailure, /* see SalReason for more details */
SalErrorUnknown
} SalError;
typedef enum SalReason{
SalReasonDeclined,
SalReasonBusy,
SalReasonRedirect,
SalReasonTemporarilyUnavailable,
SalReasonNotFound,
SalReasonDoNotDisturb,
SalReasonMedia,
SalReasonForbidden,
SalReasonUnknown
}SalReason;
typedef enum SalPresenceStatus{
SalPresenceOffline,
SalPresenceOnline,
SalPresenceBusy,
SalPresenceBerightback,
SalPresenceAway,
SalPresenceOnthephone,
SalPresenceOuttolunch,
SalPresenceDonotdisturb,
SalPresenceMoved,
SalPresenceAltService,
}SalPresenceStatus;
typedef enum SalSubscribeState{
SalSubscribeActive,
SalSubscribeTerminated
}SalSubscribeState;
typedef void (*SalOnCallReceived)(SalOp *op);
typedef void (*SalOnCallRinging)(SalOp *op);
typedef void (*SalOnCallAccepted)(SalOp *op);
typedef void (*SalOnCallAck)(SalOp *op);
typedef void (*SalOnCallUpdated)(SalOp *op);
typedef void (*SalOnCallTerminated)(SalOp *op, const char *from);
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details);
typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered);
typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details);
typedef void (*SalOnVfuRequest)(SalOp *op);
typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf);
typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto);
typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg);
typedef void (*SalOnNotify)(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg);
typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from);
typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from);
typedef void (*SalOnInternalMsg)(Sal *sal, const char *msg);
typedef void (*SalOnPingReply)(SalOp *salop);
typedef struct SalCallbacks{
SalOnCallReceived call_received;
SalOnCallRinging call_ringing;
SalOnCallAccepted call_accepted;
SalOnCallAck call_ack;
SalOnCallUpdated call_updated;
SalOnCallTerminated call_terminated;
SalOnCallFailure call_failure;
SalOnAuthRequested auth_requested;
SalOnAuthSuccess auth_success;
SalOnRegisterSuccess register_success;
SalOnRegisterFailure register_failure;
SalOnVfuRequest vfu_request;
SalOnDtmfReceived dtmf_received;
SalOnRefer refer_received;
SalOnTextReceived text_received;
SalOnNotify notify;
SalOnSubscribeReceived subscribe_received;
SalOnSubscribeClosed subscribe_closed;
SalOnInternalMsg internal_message;
SalOnPingReply ping_reply;
}SalCallbacks;
typedef struct SalAuthInfo{
char *username;
char *userid;
char *password;
char *realm;
}SalAuthInfo;
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);
void sal_set_user_agent(Sal *ctx, const char *user_agent);
void sal_use_session_timers(Sal *ctx, int expires);
int sal_iterate(Sal *sal);
MSList * sal_get_pending_auths(Sal *sal);
/*create an operation */
SalOp * sal_op_new(Sal *sal);
/*generic SalOp API, working for all operations */
Sal *sal_op_get_sal(const SalOp *op);
void sal_op_set_contact(SalOp *op, const char *contact);
void sal_op_set_route(SalOp *op, const char *route);
void sal_op_set_from(SalOp *op, const char *from);
void sal_op_set_to(SalOp *op, const char *to);
void sal_op_release(SalOp *h);
void sal_op_authenticate(SalOp *h, const SalAuthInfo *info);
void sal_op_set_user_pointer(SalOp *h, void *up);
int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username);
const char *sal_op_get_from(const SalOp *op);
const char *sal_op_get_to(const SalOp *op);
const char *sal_op_get_contact(const SalOp *op);
const char *sal_op_get_route(const SalOp *op);
const char *sal_op_get_proxy(const SalOp *op);
/*for incoming requests, returns the origin of the packet as a sip uri*/
const char *sal_op_get_network_origin(const SalOp *op);
void *sal_op_get_user_pointer(const SalOp *op);
/*Call API*/
int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc);
int sal_call(SalOp *h, const char *from, const char *to);
int sal_call_notify_ringing(SalOp *h);
int sal_call_accept(SalOp*h);
int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/);
SalMediaDescription * sal_call_get_final_media_description(SalOp *h);
int sal_refer(SalOp *h, const char *refer_to);
int sal_call_send_dtmf(SalOp *h, char dtmf);
int sal_call_terminate(SalOp *h);
/*Registration*/
int sal_register(SalOp *op, const char *proxy, const char *from, int expires);
int sal_unregister(SalOp *h);
/*Messaging */
int sal_text_send(SalOp *op, const char *from, const char *to, const char *text);
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to);
int sal_unsubscribe(SalOp *op);
int sal_subscribe_accept(SalOp *op);
int sal_subscribe_decline(SalOp *op);
int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message);
int sal_notify_close(SalOp *op);
/*presence publish */
int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status);
/*ping: main purpose is to obtain its own contact address behind firewalls*/
int sal_ping(SalOp *op, const char *from, const char *to);
#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n);
#define payload_type_get_number(pt) ((int)(long)(pt)->user_data)
/*misc*/
void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen);
/*internal API */
void __sal_op_init(SalOp *b, Sal *sal);
void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/);
void __sal_op_free(SalOp *b);
#endif

1559
coreapi/sal_eXosip2.c Normal file

File diff suppressed because it is too large Load diff

76
coreapi/sal_eXosip2.h Normal file
View file

@ -0,0 +1,76 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef sal_exosip2_h
#define sal_exosip2_h
#include "sal.h"
#include <eXosip2/eXosip.h>
sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal);
int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc);
struct Sal{
SalCallbacks callbacks;
MSList *registers;/*MSList of SalOp */
MSList *out_subscribes;/*MSList of SalOp */
MSList *in_subscribes;/*MSList of SalOp */
MSList *pending_auths;/*MSList of SalOp */
MSList *other_transactions; /*MSList of SalOp */
int running;
int session_expires;
void *up;
};
struct SalOp{
SalOpBase base;
int cid;
int did;
int tid;
int rid;
int sid;
int nid;
int expires;
SalMediaDescription *result;
sdp_message_t *sdp_answer;
eXosip_event_t *pending_auth;
osip_call_id_t *call_id; /*used for out of calls transaction in order
to retrieve the operation when receiving a response*/
bool_t supports_session_timers;
bool_t sdp_offering;
bool_t reinvite;
bool_t masquerade_via;
};
void sal_remove_out_subscribe(Sal *sal, SalOp *op);
void sal_remove_in_subscribe(Sal *sal, SalOp *op);
void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev);
void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev);
void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev);
void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev);
void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev);
void sal_exosip_fix_route(SalOp *op);
#endif

View file

@ -0,0 +1,732 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sal_eXosip2.h"
static SalOp * sal_find_out_subscribe(Sal *sal, int sid){
const MSList *elem;
SalOp *op;
for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
op=(SalOp*)elem->data;
if (op->sid==sid) return op;
}
return NULL;
}
static void sal_add_out_subscribe(Sal *sal, SalOp *op){
sal->out_subscribes=ms_list_append(sal->out_subscribes,op);
}
void sal_remove_out_subscribe(Sal *sal, SalOp *op){
sal->out_subscribes=ms_list_remove(sal->out_subscribes,op);
}
static SalOp * sal_find_in_subscribe(Sal *sal, int nid){
const MSList *elem;
SalOp *op;
for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
op=(SalOp*)elem->data;
if (op->nid==nid) return op;
}
return NULL;
}
static SalOp * sal_find_in_subscribe_by_call_id(Sal *sal, osip_call_id_t *call_id){
const MSList *elem;
SalOp *op;
for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
op=(SalOp*)elem->data;
if (op->call_id && osip_call_id_match(op->call_id,call_id)==0)
return op;
}
return NULL;
}
static void sal_add_in_subscribe(Sal *sal, SalOp *op, osip_message_t *subs){
osip_call_id_clone(subs->call_id,&op->call_id);
sal->in_subscribes=ms_list_append(sal->in_subscribes,op);
}
void sal_remove_in_subscribe(Sal *sal, SalOp *op){
sal->in_subscribes=ms_list_remove(sal->in_subscribes,op);
}
int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
osip_message_t *sip=NULL;
if (from)
sal_op_set_from(op,from);
if (to)
sal_op_set_to(op,to);
eXosip_lock();
eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op),
sal_op_get_from(op),sal_op_get_route(op));
osip_message_set_content_type(sip,"text/plain");
osip_message_set_body(sip,msg,strlen(msg));
eXosip_message_send_request(sip);
eXosip_unlock();
return 0;
}
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
osip_message_t *msg;
if (from)
sal_op_set_from(op,from);
if (to)
sal_op_set_to(op,to);
sal_exosip_fix_route(op);
eXosip_lock();
eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op),
sal_op_get_route(op),"presence",600);
op->sid=eXosip_subscribe_send_initial_request(msg);
eXosip_unlock();
if (op->sid==-1){
osip_message_free(msg);
return -1;
}
sal_add_out_subscribe(op->base.root,op);
return 0;
}
int sal_unsubscribe(SalOp *op){
osip_message_t *msg=NULL;
if (op->did==-1){
ms_error("cannot unsubscribe, no dialog !");
return -1;
}
eXosip_lock();
eXosip_subscribe_build_refresh_request(op->did,&msg);
if (msg){
osip_message_set_expires(msg,"0");
eXosip_subscribe_send_refresh_request(op->did,msg);
}else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i",
op->sid,op->did);
eXosip_unlock();
return 0;
}
int sal_subscribe_accept(SalOp *op){
osip_message_t *msg;
eXosip_lock();
eXosip_insubscription_build_answer(op->tid,202,&msg);
eXosip_insubscription_send_answer(op->tid,202,msg);
eXosip_unlock();
return 0;
}
int sal_subscribe_decline(SalOp *op){
eXosip_lock();
eXosip_insubscription_send_answer(op->tid,401,NULL);
eXosip_unlock();
return 0;
}
static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
{
char buf[1000];
#ifdef SUPPORT_MSN
int atom_id = 1000;
#endif
char *contact_info;
osip_contact_t *ct=NULL;
osip_message_get_contact(notify,0,&ct);
osip_contact_to_str(ct,&contact_info);
#ifdef SUPPORT_MSN
if (online_status==SalPresenceOnline)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"online\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceBusy)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inuse\" />\n\
<msnsubstatus substatus=\"busy\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceBerightback)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"berightback\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceAway)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"away\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inuse\" />\n\
<msnsubstatus substatus=\"onthephone\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceOuttolunch)
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"outtolunch\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else
{
sprintf(buf, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence\n\
PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"away\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
osip_message_set_body(notify, buf, strlen(buf));
osip_message_set_content_type(notify, "application/xpidf+xml");
#else
if (online_status==SalPresenceOnline)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>online</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceBusy)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>busy</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>busy</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceBerightback)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>in-transit</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>be right back</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceAway)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>away</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>away</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>on-the-phone</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>on the phone</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceOuttolunch)
{
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>meal</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>out to lunch</note>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else
{
/* */
sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n%s",
contact_info,
"<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>closed</basic>\n\
<es:activities>\n\
<es:activity>permanent-absence</es:activity>\n\
</es:activities>\n\
</status>\n\
</tuple>\n\
\n</presence>\n");
}
osip_message_set_body(notify, buf, strlen(buf));
osip_message_set_content_type(notify, "application/pidf+xml");
#endif
osip_free(contact_info);
}
int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
osip_message_t *msg;
eXosip_ss_t ss=EXOSIP_SUBCRSTATE_ACTIVE;
if (op->nid==-1){
ms_warning("Cannot notify, subscription was closed.");
return -1;
}
eXosip_lock();
eXosip_insubscription_build_notify(op->did,ss,DEACTIVATED,&msg);
if (msg!=NULL){
const char *identity=sal_op_get_contact(op);
if (identity==NULL) identity=sal_op_get_to(op);
osip_message_set_contact(msg,identity);
add_presence_body(msg,status);
eXosip_insubscription_send_request(op->did,msg);
}else ms_error("could not create notify for incoming subscription.");
eXosip_unlock();
return 0;
}
int sal_notify_close(SalOp *op){
osip_message_t *msg=NULL;
eXosip_lock();
eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg);
if (msg!=NULL){
const char *identity=sal_op_get_contact(op);
if (identity==NULL) identity=sal_op_get_to(op);
osip_message_set_contact(msg,identity);
add_presence_body(msg,SalPresenceOffline);
eXosip_insubscription_send_request(op->did,msg);
}else ms_error("sal_notify_close(): could not create notify for incoming subscription"
" did=%i, nid=%i",op->did,op->nid);
eXosip_unlock();
return 0;
}
int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus presence_mode){
osip_message_t *pub;
int i;
char buf[1024];
if (presence_mode==SalPresenceOnline)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>online</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==SalPresenceBusy
||presence_mode==SalPresenceDonotdisturb)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>busy</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>busy</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==SalPresenceBerightback)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>in-transit</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>be right back</note>\n\
</tuple>\n\
</presence>",
from,from);
}
else if (presence_mode==SalPresenceAway
||presence_mode==SalPresenceMoved)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>away</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>away</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==SalPresenceOnthephone)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>on-the-phone</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>on the phone</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else if (presence_mode==SalPresenceOuttolunch)
{
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>open</basic>\n\
<es:activities>\n\
<es:activity>meal</es:activity>\n\
</es:activities>\n\
</status>\n\
<contact priority=\"0.8\">%s</contact>\n\
<note>out to lunch</note>\n\
</tuple>\n\
</presence>",
from, from);
}
else{
/* offline */
snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
entity=\"%s\">\n%s",
from,
"<tuple id=\"sg89ae\">\n\
<status>\n\
<basic>closed</basic>\n\
<es:activities>\n\
<es:activity>permanent-absence</e:activity>\n\
</es:activities>\n\
</status>\n\
</tuple>\n\
\n</presence>\n");
}
i = eXosip_build_publish(&pub,from, to, NULL, "presence", "1800", "application/pidf+xml", buf);
if (i<0){
ms_warning("Failed to build publish request.");
return -1;
}
eXosip_lock();
i = eXosip_publish(pub, to); /* should update the sip-if-match parameter
from sip-etag from last 200ok of PUBLISH */
eXosip_unlock();
if (i<0){
ms_message("Failed to send publish request.");
return -1;
}
return 0;
}
static void _sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){
SalOp *op=sal_op_new(sal);
char *tmp;
op->did=ev->did;
op->tid=ev->tid;
op->nid=ev->nid;
osip_from_to_str(ev->request->from,&tmp);
sal_op_set_from(op,tmp);
ms_free(tmp);
osip_from_to_str(ev->request->to,&tmp);
sal_op_set_to(op,tmp);
ms_free(tmp);
sal_add_in_subscribe(sal,op,ev->request);
sal->callbacks.subscribe_received(op,sal_op_get_from(op));
}
void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){
/*workaround a bug in eXosip: incoming SUBSCRIBES within dialog with expires: 0 are
recognized as new incoming subscribes*/
SalOp *op=sal_find_in_subscribe_by_call_id(sal,ev->request->call_id);
if (op){
osip_header_t *h;
osip_message_header_get_byname(ev->request,"expires",0,&h);
if (h && h->hvalue && atoi(h->hvalue)==0){
ms_warning("This susbscribe is not a new one but terminates an old one.");
ev->did=op->did;
ev->nid=op->nid;
sal_exosip_subscription_closed(sal,ev);
}else {
osip_message_t *msg=NULL;
ms_warning("Probably a refresh subscribe");
eXosip_lock();
eXosip_insubscription_build_answer(ev->tid,202,&msg);
eXosip_insubscription_send_answer(ev->tid,202,msg);
eXosip_unlock();
}
}else _sal_exosip_subscription_recv(sal,ev);
}
void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
SalOp *op=sal_find_out_subscribe(sal,ev->sid);
char *tmp;
osip_from_t *from=NULL;
osip_body_t *body=NULL;
SalPresenceStatus estatus=SalPresenceOffline;
ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid);
if (op==NULL){
ms_error("No operation related to this notify !");
return;
}
if (ev->request==NULL) return;
from=ev->request->from;
osip_message_get_body(ev->request,0,&body);
if (body==NULL){
ms_error("No body in NOTIFY");
return;
}
osip_from_to_str(from,&tmp);
if (strstr(body->body,"pending")!=NULL){
estatus=SalPresenceOffline;
}else if (strstr(body->body,"busy")!=NULL){
estatus=SalPresenceBusy;
}else if (strstr(body->body,"berightback")!=NULL
|| strstr(body->body,"in-transit")!=NULL ){
estatus=SalPresenceBerightback;
}else if (strstr(body->body,"away")!=NULL){
estatus=SalPresenceAway;
}else if (strstr(body->body,"onthephone")!=NULL
|| strstr(body->body,"on-the-phone")!=NULL){
estatus=SalPresenceOnthephone;
}else if (strstr(body->body,"outtolunch")!=NULL
|| strstr(body->body,"meal")!=NULL){
estatus=SalPresenceOuttolunch;
}else if (strstr(body->body,"closed")!=NULL){
estatus=SalPresenceOffline;
}else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) {
estatus=SalPresenceOnline;
}else{
estatus=SalPresenceOffline;
}
ms_message("We are notified that %s has online status %i",tmp,estatus);
if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) {
sal_remove_out_subscribe(sal,op);
op->sid=-1;
op->did=-1;
ms_message("And outgoing subscription terminated by remote.");
}
sal->callbacks.notify(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL);
osip_free(tmp);
}
void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){
SalOp *op=sal_find_out_subscribe(sal,ev->sid);
if (op==NULL){
ms_error("Subscription answered but no associated op !");
return;
}
op->did=ev->did;
}
void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev){
SalOp *op=sal_find_in_subscribe(sal,ev->nid);
char *tmp;
if (op==NULL){
ms_error("Incoming subscription closed but no associated op !");
return;
}
sal_remove_in_subscribe(sal,op);
op->nid=-1;
op->did=-1;
if (ev->request){
osip_from_to_str(ev->request->from,&tmp);
sal->callbacks.subscribe_closed(op,tmp);
osip_free(tmp);
}
}
void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){
SalOp *op=sal_find_out_subscribe(sal,ev->sid);
if (op==NULL){
ms_error("Subscription closed but no associated op !");
return;
}
sal_remove_out_subscribe(sal,op);
op->sid=-1;
op->did=-1;
sal->callbacks.notify(op,SalSubscribeTerminated, SalPresenceOffline,NULL);
}

288
coreapi/sal_eXosip2_sdp.c Normal file
View file

@ -0,0 +1,288 @@
/*
linphone
Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ortp/b64.h"
#include "sal.h"
#include <eXosip2/eXosip.h>
#define keywordcmp(key,b) strncmp(key,b,sizeof(key))
#ifdef FOR_LATER
static char *make_relay_session_id(const char *username, const char *relay){
/*ideally this should be a hash of the parameters with a random part*/
char tmp[128];
int s1=(int)random();
int s2=(int)random();
long long int res=((long long int)s1)<<32 | (long long int) s2;
void *src=&res;
b64_encode(src, sizeof(long long int), tmp, sizeof(tmp));
return osip_strdup(tmp);
}
static void add_relay_info(sdp_message_t *sdp, int mline, const char *relay, const char *relay_session_id){
if (relay) sdp_message_a_attribute_add(sdp, mline,
osip_strdup ("relay-addr"),osip_strdup(relay));
if (relay_session_id) sdp_message_a_attribute_add(sdp, mline,
osip_strdup ("relay-session-id"), osip_strdup(relay_session_id));
}
#endif
static char * int_2char(int a){
char *p=osip_malloc(16);
snprintf(p,16,"%i",a);
return p;
}
/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/
static const char *sdp_message_a_attr_value_get_with_pt(sdp_message_t *sdp,int pos,int pt,const char *field)
{
int i,tmppt=0,scanned=0;
char *tmp;
sdp_attribute_t *attr;
for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){
if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){
int nb = sscanf(attr->a_att_value,"%i %n",&tmppt,&scanned);
/* the return value may depend on how %n is interpreted by the libc: see manpage*/
if (nb == 1 || nb==2 ){
if (pt==tmppt){
tmp=attr->a_att_value+scanned;
if (strlen(tmp)>0)
return tmp;
}
}else ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb);
}
}
return NULL;
}
#ifdef FOR_LATER
/* return the value of attr "field" */
static const char *sdp_message_a_attr_value_get(sdp_message_t *sdp,int pos,const char *field)
{
int i;
sdp_attribute_t *attr;
for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){
if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){
return attr->a_att_value;
}
}
return NULL;
}
#endif
static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){
int i,ret;
sdp_attribute_t *attr;
for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){
if (keywordcmp("ptime",attr->a_att_field)==0){
int nb = sscanf(attr->a_att_value,"%i",&ret);
/* the return value may depend on how %n is interpreted by the libc: see manpage*/
if (nb == 1){
return ret;
}else ms_warning("sdp has a strange a=ptime line (%s) ",attr->a_att_value);
}
}
return 0;
}
static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
{
sdp_message_t *local;
int inet6;
sdp_message_init (&local);
if (strchr(desc->addr,':')!=NULL){
inet6=1;
}else inet6=0;
sdp_message_v_version_set (local, osip_strdup ("0"));
sdp_message_o_origin_set (local, osip_strdup (desc->username),
osip_strdup ("123456"), osip_strdup ("654321"),
osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr));
sdp_message_s_name_set (local, osip_strdup ("A conversation"));
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr), NULL, NULL);
sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0"));
return local;
}
static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt)
{
char attr[256];
sdp_message_m_payload_add (msg,line, int_2char (payload_type_get_number(pt)));
if (pt->channels>0)
snprintf (attr,sizeof(attr),"%i %s/%i/%i", payload_type_get_number(pt),
pt->mime_type, pt->clock_rate,pt->channels);
else
snprintf (attr,sizeof(attr),"%i %s/%i", payload_type_get_number(pt),
pt->mime_type, pt->clock_rate);
sdp_message_a_attribute_add (msg, line,
osip_strdup ("rtpmap"), osip_strdup(attr));
if (pt->recv_fmtp != NULL)
{
snprintf (attr,sizeof(attr),"%i %s", payload_type_get_number(pt),pt->recv_fmtp);
sdp_message_a_attribute_add (msg, line, osip_strdup ("fmtp"),
osip_strdup(attr));
}
}
static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){
const char *mt=desc->type==SalAudio ? "audio" : "video";
const MSList *elem;
const char *addr;
int port;
if (desc->candidates[0].addr[0]!='\0'){
addr=desc->candidates[0].addr;
port=desc->candidates[0].port;
}else{
addr=desc->addr;
port=desc->port;
}
/*only add a c= line within the stream description if address are differents*/
if (strcmp(addr,sdp_message_c_addr_get(msg, -1, 0))!=0){
bool_t inet6;
if (strchr(addr,':')!=NULL){
inet6=TRUE;
}else inet6=FALSE;
sdp_message_c_connection_add (msg, lineno,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (addr), NULL, NULL);
}
sdp_message_m_media_add (msg, osip_strdup (mt),
int_2char (port), NULL,
osip_strdup ("RTP/AVP"));
if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"),
int_2char(desc->bandwidth));
if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"),
int_2char(desc->ptime));
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
add_payload(msg, lineno, (PayloadType*)elem->data);
}
}
sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){
int i;
sdp_message_t *msg=create_generic_sdp(desc);
for(i=0;i<desc->nstreams;++i){
add_line(msg,i,&desc->streams[i]);
}
return msg;
}
static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){
if (rtpmap==NULL){
PayloadType *refpt=rtp_profile_get_payload(&av_profile,payload_type_get_number(pt));
if (refpt){
pt->mime_type=ms_strdup(refpt->mime_type);
pt->clock_rate=refpt->clock_rate;
}else{
ms_error("payload number %i has no rtpmap and is unknown in AV Profile, ignored.",
payload_type_get_number(pt));
return -1;
}
}else{
char *mime=ms_strdup(rtpmap);
char *p=strchr(mime,'/');
if (p){
char *chans;
*p='\0';
p++;
chans=strchr(p,'/');
if (chans){
*chans='\0';
chans++;
pt->channels=atoi(chans);
}else pt->channels=1;
pt->clock_rate=atoi(p);
}
pt->mime_type=mime;
}
return 0;
}
int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
int i,j;
const char *mtype,*proto,*port,*addr,*number;
sdp_bandwidth_t *sbw=NULL;
addr=sdp_message_c_addr_get (msg, -1, 0);
if (addr)
strncpy(desc->addr,addr,sizeof(desc->addr));
/* for each m= line */
for (i=0; !sdp_message_endof_media (msg, i) && i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++)
{
SalStreamDescription *stream=&desc->streams[i];
memset(stream,0,sizeof(*stream));
mtype = sdp_message_m_media_get(msg, i);
proto = sdp_message_m_proto_get (msg, i);
port = sdp_message_m_port_get(msg, i);
stream->proto=SalProtoUnknown;
if (proto){
if (strcasecmp(proto,"RTP/AVP")==0)
stream->proto=SalProtoRtpAvp;
else if (strcasecmp(proto,"RTP/SAVP")==0){
stream->proto=SalProtoRtpSavp;
}
}
addr = sdp_message_c_addr_get (msg, i, 0);
if (addr != NULL)
strncpy(stream->addr,addr,sizeof(stream->addr));
if (port)
stream->port=atoi(port);
stream->ptime=_sdp_message_get_a_ptime(msg,i);
if (strcasecmp("audio", mtype) == 0){
stream->type=SalAudio;
}else if (strcasecmp("video", mtype) == 0){
stream->type=SalVideo;
}else stream->type=SalOther;
for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){
if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth);
}
/* for each payload type */
for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){
const char *rtpmap,*fmtp;
int ptn=atoi(number);
PayloadType *pt=payload_type_new();
payload_type_set_number(pt,ptn);
/* get the rtpmap associated to this codec, if any */
rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap");
payload_type_fill_from_rtpmap(pt,rtpmap);
/* get the fmtp, if any */
fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp");
payload_type_set_send_fmtp(pt,fmtp);
stream->payloads=ms_list_append(stream->payloads,pt);
ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
pt->send_fmtp ? pt->send_fmtp : "");
}
}
desc->nstreams=i;
return 0;
}

View file

@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#include "linphonecore.h"
#include "private.h"
#include <ctype.h>
static void sip_login_init_instance(SipSetupContext *ctx){

View file

@ -39,7 +39,6 @@ typedef struct _status_picture_tab_t{
} status_picture_tab_t;
status_picture_tab_t status_picture_tab[]={
{ LINPHONE_STATUS_UNKNOWN, "sip-closed.png" },
{ LINPHONE_STATUS_ONLINE, "sip-online.png" },
{ LINPHONE_STATUS_BUSY, "sip-busy.png" },
{ LINPHONE_STATUS_BERIGHTBACK, "sip-bifm.png" },
@ -51,7 +50,6 @@ status_picture_tab_t status_picture_tab[]={
{ LINPHONE_STATUS_ALT_SERVICE, "sip-closed.png" },
{ LINPHONE_STATUS_OFFLINE, "sip-away.png" },
{ LINPHONE_STATUS_PENDING, "sip-wfa.png" },
{ LINPHONE_STATUS_CLOSED, "sip-closed.png" },
{ LINPHONE_STATUS_END, NULL },
};
@ -104,7 +102,7 @@ static void linphone_gtk_set_selection_to_uri_bar(GtkTreeView *treeview){
if (gtk_tree_selection_get_selected (select, &model, &iter))
{
gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1);
friend=linphone_address_as_string(linphone_friend_get_uri(lf));
friend=linphone_address_as_string(linphone_friend_get_address(lf));
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),friend);
ms_free(friend);
}
@ -134,8 +132,7 @@ static GtkWidget * create_presence_menu(){
GdkPixbuf *pbuf;
status_picture_tab_t *t;
for(t=status_picture_tab;t->img!=NULL;++t){
if (t->status==LINPHONE_STATUS_UNKNOWN ||
t->status==LINPHONE_STATUS_PENDING){
if (t->status==LINPHONE_STATUS_PENDING){
continue;
}
menu_item=gtk_image_menu_item_new_with_label(linphone_online_status_to_string(t->status));
@ -309,7 +306,7 @@ void linphone_gtk_show_friends(void){
for(itf=linphone_core_get_friend_list(core);itf!=NULL;itf=ms_list_next(itf)){
LinphoneFriend *lf=(LinphoneFriend*)itf->data;
const LinphoneAddress *f_uri=linphone_friend_get_uri(lf);
const LinphoneAddress *f_uri=linphone_friend_get_address(lf);
char *uri=linphone_address_as_string(f_uri);
const char *name=linphone_address_get_display_name(f_uri);
const char *display=name;
@ -376,7 +373,7 @@ void linphone_gtk_show_contact(LinphoneFriend *lf){
GtkWidget *w=linphone_gtk_create_window("contact");
char *uri;
const char *name;
const LinphoneAddress *f_uri=linphone_friend_get_uri(lf);
const LinphoneAddress *f_uri=linphone_friend_get_address(lf);
uri=linphone_address_as_string_uri_only(f_uri);
name=linphone_address_get_display_name(f_uri);
if (uri) {
@ -419,7 +416,7 @@ void linphone_gtk_chat_selected(GtkWidget *item){
{
char *uri;
gtk_tree_model_get (model, &iter,FRIEND_ID , &lf, -1);
uri=linphone_address_as_string(linphone_friend_get_uri(lf));
uri=linphone_address_as_string(linphone_friend_get_address(lf));
linphone_gtk_create_chatroom(uri);
ms_free(uri);
}

View file

@ -163,7 +163,7 @@ static void linphone_gtk_log_file(OrtpLogLevel lev, const char *msg)
/* lc->config will turn NULL at exit, close the file to flush and
return to stop logging */
if (lc->config == NULL) {
if (linphone_core_get_config(lc) == NULL) {
linphone_gtk_log_uninit();
return;
}

View file

@ -60,6 +60,7 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
LinphoneAddress *from;
LinphoneCore *lc=linphone_gtk_get_core();
int nettype;
const char *passwd=NULL;
if (linphone_core_get_download_bandwidth(lc)==512 &&
@ -91,8 +92,9 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
if (linphone_address_get_username(from)[0]!='?')
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")),
linphone_address_get_username(from));
if (ai) passwd=linphone_auth_info_get_passwd(ai);
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password")),
ai!=NULL ? ai->passwd : "");
passwd!=NULL ? passwd : "");
linphone_address_destroy(from);
}

View file

@ -42,7 +42,7 @@ static GtkWidget *the_ui=NULL;
static void linphone_gtk_show(LinphoneCore *lc);
static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from);
static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from);
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img);
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
@ -208,7 +208,7 @@ static const char *linphone_gtk_get_factory_config_file(){
}
static void linphone_gtk_init_liblinphone(const char *config_file,
const char *factory_config_file) {
const char *factory_config_file) {
linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
@ -720,7 +720,8 @@ static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){
}
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid, const char *url, const char *status, const char *img){
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
linphone_gtk_show_friends();
}
static void linphone_gtk_new_subscriber_response(GtkWidget *dialog, guint response_id, LinphoneFriend *lf){

View file

@ -295,7 +295,7 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl
gchar *color;
const char *params="";
struct _PayloadType *pt=(struct _PayloadType *)elem->data;
if (payload_type_enabled(pt)) status=_("Enabled");
if (linphone_core_payload_type_enabled(linphone_gtk_get_core(),pt)) status=_("Enabled");
else status=_("Disabled");
if (linphone_core_check_payload_type_usability(linphone_gtk_get_core(),pt)) color="blue";
else color="red";
@ -311,7 +311,7 @@ static void linphone_gtk_show_codecs(GtkTreeView *listview, const MSList *codecl
CODEC_PARAMS,params,
CODEC_PRIVDATA,(gpointer)pt,
CODEC_COLOR,(gpointer)color,
CODEC_INFO,(gpointer)payload_type_get_description(pt),
CODEC_INFO,(gpointer)linphone_core_get_payload_type_description(linphone_gtk_get_core(),pt),
-1);
}
@ -433,7 +433,7 @@ static void linphone_gtk_codec_set_enable(GtkWidget *button, gboolean enabled){
if (gtk_tree_selection_get_selected(sel,&mod,&iter)){
store=GTK_LIST_STORE(mod);
gtk_tree_model_get(mod,&iter,CODEC_PRIVDATA,&pt,-1);
payload_type_set_enable(pt,enabled);
linphone_core_enable_payload_type(linphone_gtk_get_core(),pt,enabled);
gtk_list_store_set(store,&iter,CODEC_STATUS, enabled ? _("Enabled") : _("Disabled"), -1);
}
}

View file

@ -24,6 +24,10 @@ AC_CHECK_LIB([eXosip2],[eXosip_get_version],
[AC_DEFINE([HAVE_EXOSIP_GET_VERSION],[1],[Defined when eXosip_get_version is available])],
[],
[-losipparser2 -losip2 ])
AC_CHECK_LIB([eXosip2],[eXosip_call_get_reference],
[],
[AC_MSG_ERROR([Could not find eXosip_call_get_reference() in eXosip2 !])],
[-losipparser2 -losip2 ])
dnl AC_CHECK_LIB([eXosip2],[eXosip_get_naptr],
dnl [AC_DEFINE([HAVE_EXOSIP_NAPTR_SUPPORT],[1],[Defined when eXosip_get_naptr is available])],
dnl [],