implement presence

This commit is contained in:
Jehan Monnier 2012-12-13 18:05:16 +01:00
parent 6c323ddc08
commit 510f3b7200
13 changed files with 817 additions and 49 deletions

View file

@ -59,7 +59,7 @@
<folderInfo id="0.2131511368.593515799." name="/" resourcePath="">
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1930099439" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
<targetPlatform binaryParser="org.eclipse.cdt.core.MachO64" id="org.eclipse.cdt.build.core.prefbase.toolchain.1930099439.714963030" name=""/>
<builder arguments="CFLAGS=&quot;-g -Wall -Werror -Wno-deprecated-declarations&quot; V=1" command="make" id="org.eclipse.cdt.build.core.settings.default.builder.896899734" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<builder arguments="CFLAGS=&quot;-g -Wall -Werror -Wno-deprecated-declarations -Wno-unused-function&quot; V=1" command="make" id="org.eclipse.cdt.build.core.settings.default.builder.896899734" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.1682581923" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.730520342" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.552841386" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>

View file

@ -46,7 +46,8 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \
bellesip_sal/sal_op_call.c \
bellesip_sal/sal_op_registration.c \
bellesip_sal/sal_sdp.c \
bellesip_sal/sal_op_message.c
bellesip_sal/sal_op_message.c \
bellesip_sal/sal_op_presence.c
else
liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\
sal_eXosip2_sdp.c \

View file

@ -35,12 +35,28 @@ static void sal_add_pending_auth(Sal *sal, SalOp *op){
}
void sal_process_authentication(SalOp *op, belle_sip_response_t *response) {
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_AUTHORIZATION);
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(op->request),BELLE_SIP_PROXY_AUTHORIZATION);
if (belle_sip_provider_add_authorization(op->base.root->prov,op->request,response)) {
sal_op_resend_request(op,op->request);
belle_sip_request_t* request;
bool_t is_within_dialog=FALSE;
if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) {
request = belle_sip_dialog_create_request_from(op->dialog,(const belle_sip_request_t *)op->request);
is_within_dialog=TRUE;
} else {
request=op->request;
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION);
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION);
}
if (belle_sip_provider_add_authorization(op->base.root->prov,request,response)) {
if (is_within_dialog) {
sal_op_resend_request(op,request);
} else {
sal_op_send_request(op,request);
}
}else {
ms_message("No auth info found for [%s]",sal_op_get_from(op));
if (is_within_dialog) {
belle_sip_object_unref(request);
}
sal_add_pending_auth(op->base.root,op);
}
@ -76,6 +92,10 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev
op=sal_op_new((Sal*)sal);
op->dir=SalOpDirIncoming;
sal_op_call_fill_cbs(op);
} else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) {
op=sal_op_new((Sal*)sal);
op->dir=SalOpDirIncoming;
sal_op_presence_fill_cbs(op);
} else if (strcmp("MESSAGE",belle_sip_request_get_method(req))==0) {
content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
if (content_type

View file

@ -66,6 +66,7 @@ struct SalOp{
bool_t supports_session_timers;
SalOpSate_t state;
SalOpDir_t dir;
belle_sip_refresher_t* refresher;
};
belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal);
@ -80,4 +81,9 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request);
void sal_op_resend_request(SalOp* op, belle_sip_request_t* request);
void sal_process_authentication(SalOp *op, belle_sip_response_t *response);
bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size);
/*presence*/
void sal_op_presence_fill_cbs(SalOp*op);
#endif /* SAL_IMPL_H_ */

View file

@ -88,40 +88,6 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) {
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
ms_fatal("sal_subscribe_presence not implemented yet");
return -1;
}
int sal_unsubscribe(SalOp *op){
ms_fatal("sal_unsubscribe not implemented yet");
return -1;
}
int sal_subscribe_accept(SalOp *op){
ms_fatal("sal_subscribe_accept not implemented yet");
return -1;
}
int sal_subscribe_decline(SalOp *op){
ms_fatal("sal_subscribe_decline not implemented yet");
return -1;
}
int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
ms_fatal("sal_notify_presence not implemented yet");
return -1;
}
int sal_notify_close(SalOp *op){
ms_fatal("sal_notify_close not implemented yet");
return -1;
}
/*presence publish */
int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){
ms_fatal("sal_publish not implemented yet");
return -1;
}
/*ping: main purpose is to obtain its own contact address behind firewalls*/
int sal_ping(SalOp *op, const char *from, const char *to){
ms_fatal("sal_ping not implemented yet");
@ -141,6 +107,11 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) {
belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
sal_op_send_request(op,request);
}
static bool_t is_request_creating_dialog(belle_sip_request_t* request) {
return strcmp("INVITE",belle_sip_request_get_method(request))==0
||
strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0;
}
int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
belle_sip_client_transaction_t* client_transaction;
belle_sip_provider_t* prov=op->base.root->prov;
@ -155,7 +126,7 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
client_transaction = belle_sip_provider_create_client_transaction(prov,request);
belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op);
/*in case DIALOG is in state NULL create a new dialog*/
if (!op->dialog && strcmp("INVITE",belle_sip_request_get_method(request))==0) {
if (!op->dialog && is_request_creating_dialog(request)) {
op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction));
op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/
belle_sip_dialog_set_application_data(op->dialog,op);
@ -167,3 +138,65 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
return belle_sip_client_transaction_send_request(client_transaction);
}
/*return TRUE if error code*/
bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) {
int code = belle_sip_response_get_status_code(response);
belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
*sal_err=SalErrorUnknown;
*sal_reason = SalReasonUnknown;
if (reason_header){
snprintf(reason
,reason_size
,"%s %s"
,belle_sip_response_get_reason_phrase(response)
,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header)));
} else {
strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size);
}
if (code >=400) {
switch(code) {
case 400:
*sal_err=SalErrorUnknown;
break;
case 404:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonNotFound;
break;
case 415:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonMedia;
break;
case 422:
ms_error ("422 not implemented yet");;
break;
case 480:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonTemporarilyUnavailable;
break;
case 486:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonBusy;
break;
case 487:
break;
case 600:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonDoNotDisturb;
break;
case 603:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonDeclined;
break;
default:
if (code>0){
*sal_err=SalErrorFailure;
*sal_reason=SalReasonUnknown;
}else *sal_err=SalErrorNoResponse;
/* no break */
}
return TRUE;
} else {
return FALSE;
}
}

View file

@ -0,0 +1,628 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sal_impl.h"
typedef enum {
PIDF = 0,
RFCxxxx = 1,
MSOLDPRES = 2
} presence_type_t;
/*
* REVISIT: this static variable forces every dialog to use the same presence description type depending
* on what is received on a single dialog...
*/
static presence_type_t presence_style = PIDF;
static void mk_presence_body (const SalPresenceStatus online_status, const char *contact_info,
char *buf, size_t buflen, presence_type_t ptype) {
switch (ptype) {
case RFCxxxx: {
/* definition from http://msdn.microsoft.com/en-us/library/cc246202%28PROT.10%29.aspx */
int atom_id = 1000;
if (online_status==SalPresenceOnline)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence 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\" 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 ||
online_status == SalPresenceDonotdisturb)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence 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\" 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)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence 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\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"berightback\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status == SalPresenceAway ||
online_status == SalPresenceMoved)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence 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\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"away\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence 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\" 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)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence 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\" priority=\"0.800000\">\n\
<status status=\"open\" />\n\
<msnsubstatus substatus=\"outtolunch\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence 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\" priority=\"0.800000\">\n\
<status status=\"closed\" />\n\
<msnsubstatus substatus=\"away\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
break;
}
case MSOLDPRES: {
/* Couldn't find schema http://schemas.microsoft.com/2002/09/sip/presence
* so messages format has been taken from Communigate that can send notify
* requests with this schema
*/
int atom_id = 1000;
if (online_status==SalPresenceOnline)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\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 ||
online_status == SalPresenceDonotdisturb)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\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)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\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 ||
online_status == SalPresenceMoved)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"idle\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\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)
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"inactive\" />\n\
<msnsubstatus substatus=\"outtolunch\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
else
{
snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
<!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
<presence>\n\
<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
<atom id=\"%i\">\n\
<address uri=\"%s\">\n\
<status status=\"closed\" />\n\
<msnsubstatus substatus=\"offline\" />\n\
</address>\n\
</atom>\n\
</presence>", contact_info, atom_id, contact_info);
}
break;
}
default: { /* use pidf+xml as default format, rfc4479, rfc4480, rfc3863 */
if (online_status==SalPresenceOnline)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status == SalPresenceBusy ||
online_status == SalPresenceDonotdisturb)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"sg89aep\">\n\
<rpid:activities><rpid:busy/></rpid:activities>\n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceBerightback)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"sg89aep\">\n\
<rpid:activities><rpid:in-transit/></rpid:activities>\n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status == SalPresenceAway ||
online_status == SalPresenceMoved)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"sg89aep\">\n\
<rpid:activities><rpid:away/></rpid:activities>\n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceOnthephone)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"sg89aep\">\n\
<rpid:activities><rpid:on-the-phone/></rpid:activities>\n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else if (online_status==SalPresenceOuttolunch)
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"7777\">\n\
<status><basic>open</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
<dm:person id=\"78787878\">\n\
<rpid:activities><rpid:meal/></rpid:activities>\n\
<rpid:note>Out to lunch</rpid:note> \n\
</dm:person>\n\
</presence>",
contact_info, contact_info);
}
else
{
snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
entity=\"%s\">\n\
<tuple id=\"sg89ae\">\n\
<status><basic>closed</basic></status>\n\
<contact priority=\"0.8\">%s</contact>\n\
</tuple>\n\
</presence>\n", contact_info, contact_info);
}
break;
}
} // switch
}
static void add_presence_info(belle_sip_message_t *notify, SalPresenceStatus online_status) {
char buf[1000];
char *contact_info;
size_t content_length;
belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(notify,belle_sip_header_from_t);
contact_info=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)));
mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application",presence_style?"xpidf+xml":"pidf+xml")));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(buf))));
belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),buf,content_length);
ms_free(contact_info);
}
static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
ms_error("presence_process_io_error not implemented yet");
}
static void presence_process_dialog_terminated(void *op, const belle_sip_dialog_terminated_event_t *event) {
if (((SalOp*)op)->dialog) ((SalOp*)op)->dialog=NULL;
}
static void presence_response_event(void *op_base, const belle_sip_response_event_t *event){
SalOp* op = (SalOp*)op_base;
belle_sip_dialog_state_t dialog_state;
belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
belle_sip_response_t* response=belle_sip_response_event_get_response(event);
belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
int code = belle_sip_response_get_status_code(response);
char reason[256]={0};
SalError error=SalErrorUnknown;
SalReason sr=SalReasonUnknown;
belle_sip_header_expires_t* expires;
if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) {
ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr));
op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL);
return;
}
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL:
case BELLE_SIP_DIALOG_EARLY: {
ms_error("op [%p] receive an unexpected answer [%i]",op,code);
break;
}
case BELLE_SIP_DIALOG_CONFIRMED: {
if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0) {
expires=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t);
if(op->refresher) {
belle_sip_refresher_stop(op->refresher);
belle_sip_object_unref(op->refresher);
}
if (expires>0){
op->refresher=belle_sip_client_transaction_create_refresher(client_transaction);
}
}
break;
}
case BELLE_SIP_DIALOG_TERMINATED:
if (op->refresher) {
belle_sip_refresher_stop(op->refresher);
belle_sip_object_unref(op->refresher);
op->refresher=NULL;
}
break;
default: {
ms_error("op [%p] receive answer [%i] not implemented",op,code);
}
/* no break */
}
}
static void presence_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
ms_error("presence_process_timeout not implemented yet");
}
static void presence_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
ms_error("presence_process_timeout not implemented yet");
}
static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_dialog_state_t dialog_state;
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t);
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);;
const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
SalPresenceStatus estatus=SalPresenceOffline;
SalSubscribeState sub_state;
belle_sip_response_t* resp;
belle_sip_object_ref(server_transaction);
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
op->pending_server_trans=server_transaction;
if (!op->dialog) {
op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction));
belle_sip_dialog_set_application_data(op->dialog,op);
ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
}
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL: {
op->base.root->callbacks.subscribe_received(op,sal_op_get_from(op));
break;
}
case BELLE_SIP_DIALOG_EARLY:
ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",belle_sip_request_get_method(req),op->dialog);
break;
case BELLE_SIP_DIALOG_CONFIRMED:
if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
if (body==NULL){
ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op));
return;
}
if (strstr(body,"pending")!=NULL){
estatus=SalPresenceOffline;
}else if (strstr(body,"busy")!=NULL){
estatus=SalPresenceBusy;
}else if (strstr(body,"berightback")!=NULL
|| strstr(body,"in-transit")!=NULL ){
estatus=SalPresenceBerightback;
}else if (strstr(body,"away")!=NULL
|| strstr(body,"idle")){
estatus=SalPresenceAway;
}else if (strstr(body,"onthephone")!=NULL
|| strstr(body,"on-the-phone")!=NULL){
estatus=SalPresenceOnthephone;
}else if (strstr(body,"outtolunch")!=NULL
|| strstr(body,"meal")!=NULL){
estatus=SalPresenceOuttolunch;
}else if (strstr(body,"closed")!=NULL){
estatus=SalPresenceOffline;
}else if ((strstr(body,"online")!=NULL) || (strstr(body,"open")!=NULL)) {
estatus=SalPresenceOnline;
}else{
estatus=SalPresenceOffline;
}
ms_message("We are notified that [%s] has online status %i",sal_op_get_from(op),estatus);
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
sub_state=SalSubscribeTerminated;
ms_message("And outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else
sub_state=SalSubscribeActive;
op->base.root->callbacks.notify_presence(op,sub_state, estatus,NULL);
resp=belle_sip_response_create_from_request(req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
} else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) {
/*either a refresh of an unsubscribe*/
if (expires && belle_sip_header_expires_get_expires(expires)>0) {
op->base.root->callbacks.subscribe_received(op,sal_op_get_from(op));
} else if(expires) {
ms_message("Unsubscribe received from [%s]",sal_op_get_from(op));
resp=belle_sip_response_create_from_request(req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
}
}
break;
default: {
ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
}
/* no break */
}
}
void sal_op_presence_fill_cbs(SalOp*op) {
op->callbacks.process_io_error=presence_process_io_error;
op->callbacks.process_response_event=presence_response_event;
op->callbacks.process_timeout=presence_process_timeout;
op->callbacks.process_transaction_terminated=presence_process_transaction_terminated;
op->callbacks.process_request_event=presence_process_request_event;
op->callbacks.process_dialog_terminated=presence_process_dialog_terminated;
}
/*presence publish */
int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status){
ms_fatal("sal_publish not implemented yet");
return -1;
}
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
belle_sip_request_t *req=NULL;
if (from)
sal_op_set_from(op,from);
if (to)
sal_op_set_to(op,to);
sal_op_presence_fill_cbs(op);
/*???sal_exosip_fix_route(op); make sure to ha ;lr*/
req=sal_op_build_request(op,"SUBSCRIBE");
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence"));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600)));
return sal_op_send_request(op,req);
}
int sal_unsubscribe(SalOp *op){
belle_sip_request_t* req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE");
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","Presence"));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0)));
return sal_op_send_request(op,req);
}
int sal_subscribe_accept(SalOp *op){
belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans));
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
belle_sip_response_t* resp = belle_sip_response_create_from_request(req,200);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires));
belle_sip_server_transaction_send_response(op->pending_server_trans,resp);
return 0;
}
int sal_subscribe_decline(SalOp *op){
belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),403);
belle_sip_server_transaction_send_response(op->pending_server_trans,resp);
return 0;
}
int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY");
/* belle_sip_header_address_t* identity=sal_op_get_contact_address(op);
if (identity==NULL) identity=sal_op_get_to_address(op);
_osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(msg,identity);*/
add_presence_info(BELLE_SIP_MESSAGE(notify),status); /*FIXME, what about expires ??*/
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)));
return sal_op_send_request(op,notify);
}
int sal_notify_close(SalOp *op){
belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY");
add_presence_info(BELLE_SIP_MESSAGE(notify),SalPresenceOffline); /*FIXME, what about expires ??*/
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1)));
return sal_op_send_request(op,notify);
}

View file

@ -30,11 +30,7 @@ static void register_refresh(SalOp* op) {
belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
sal_op_send_request(op,op->request);
}
static bool_t is_contact_equal(belle_sip_header_contact_t* a,belle_sip_header_contact_t* b) {
if (!a | !b) return FALSE;
return !belle_sip_uri_equals(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(a))
,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(b)));
}
static void register_response_event(void *user_ctx, const belle_sip_response_event_t *event){
belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
@ -52,7 +48,7 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve
contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT);
if (contact_header_list) {
contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)is_contact_equal, (const void*)sal_op_get_contact_address(op));
contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list,(belle_sip_compare_func)belle_sip_header_contact_equals, (const void*)sal_op_get_contact_address(op));
if (!contact_header_list) {
ms_error("no matching contact for [%s]", sal_op_get_contact(op));
} else {

View file

@ -338,8 +338,8 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
ms_warning("No sip url defined.");
return;
}
fr->lc=lc;
linphone_core_write_friends_config(lc);
if (fr->inc_subscribe_pending){
@ -390,6 +390,7 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf)
return ;
}
lc->friends=ms_list_append(lc->friends,lf);
lf->lc=lc;
if ( linphone_core_ready(lc)) linphone_friend_apply(lf,lc);
else lf->commit=TRUE;
return ;

View file

@ -414,3 +414,18 @@ const char* sal_stream_dir_to_string(SalStreamDir type) {
}
}
const char* sal_reason_to_string(const SalReason reason) {
switch (reason) {
case SalReasonDeclined : return "SalReasonDeclined";
case SalReasonBusy: return "SalReasonBusy";
case SalReasonRedirect: return "SalReasonRedirect";
case SalReasonTemporarilyUnavailable: return "SalReasonTemporarilyUnavailable";
case SalReasonNotFound: return "SalReasonNotFound";
case SalReasonDoNotDisturb: return "SalReasonDoNotDisturb";
case SalReasonMedia: return "SalReasonMedia";
case SalReasonForbidden: return "SalReasonForbidden";
case SalReasonUnknown: return "SalReasonUnknown";
default: return "Unkown reason";
}
}

View file

@ -201,6 +201,8 @@ typedef enum SalReason{
SalReasonUnknown
}SalReason;
const char* sal_reason_to_string(const SalReason reason);
typedef enum SalPresenceStatus{
SalPresenceOffline,
SalPresenceOnline,

View file

@ -84,6 +84,9 @@ typedef struct _stats {
int number_of_LinphoneCallReleased;
int number_of_LinphoneMessageReceived;
int number_of_NewSubscriptionRequest;
int number_of_NotifyReceived;
}stats;
static stats global_stat;
@ -296,7 +299,6 @@ static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCal
}
static void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) {
char* from=linphone_address_as_string(from_address);
ms_message("Message from [%s] is [%s]",from,message);
ms_free(from);
@ -304,6 +306,21 @@ static void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, cons
counters->number_of_LinphoneMessageReceived++;
}
void new_subscribtion_request(LinphoneCore *lc, LinphoneFriend *lf, const char *url){
char* from=linphone_address_as_string(linphone_friend_get_address(lf));
ms_message("New subscription request from [%s] url [%s]",from,url);
ms_free(from);
stats* counters = (stats*)linphone_core_get_user_data(lc);
counters->number_of_NewSubscriptionRequest++;
}
static void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) {
char* from=linphone_address_as_string(linphone_friend_get_address(lf));
ms_message("New Notify request from [%s] ",from);
ms_free(from);
stats* counters = (stats*)linphone_core_get_user_data(lc);
counters->number_of_NotifyReceived++;
}
static bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) {
int retry=0;
while (*counter<value && retry++ <20) {
@ -339,6 +356,8 @@ static LinphoneCoreManager* linphone_core_manager_new(const char* rc_file) {
mgr->v_table.registration_state_changed=registration_state_changed;
mgr->v_table.call_state_changed=call_state_changed;
mgr->v_table.text_received=text_message_received;
mgr->v_table.new_subscription_request=new_subscribtion_request;
mgr->v_table.notify_presence_recv=notify_presence_received;
mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1);
enable_codec(mgr->lc,"PCMU",8000);
linphone_core_set_user_data(mgr->lc,&mgr->stat);
@ -551,6 +570,37 @@ static void text_message() {
linphone_core_manager_destroy(pauline);
}
static void simple_publish() {
LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc");
LinphoneProxyConfig* proxy;
linphone_core_get_default_proxy(marie->lc,&proxy);
linphone_proxy_config_edit(proxy);
linphone_proxy_config_enable_publish(proxy,TRUE);
linphone_proxy_config_done(proxy);
linphone_core_iterate(marie->lc);
linphone_core_manager_destroy(marie);
}
static void simple_subscribe() {
LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc");
const MSList* marie_friends = linphone_core_get_friend_list(marie->lc);
CU_ASSERT_PTR_NOT_NULL_FATAL(marie_friends);
LinphoneFriend* friend = (LinphoneFriend*) marie_friends->data;
linphone_friend_edit(friend);
linphone_friend_enable_subscribes(friend,TRUE);
linphone_friend_done(friend);
CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,1));
CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_NotifyReceived,1));
linphone_core_manager_destroy(marie);
CU_ASSERT_TRUE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*wait for unsubscribe*/
linphone_core_manager_destroy(pauline);
}
int init_test_suite () {
CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit);
@ -604,6 +654,12 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit);
if (NULL == CU_add_test(pSuite, "text_message", text_message)) {
return CU_get_error();
}
if (NULL == CU_add_test(pSuite, "simple_subscribe", simple_subscribe)) {
return CU_get_error();
}
if (NULL == CU_add_test(pSuite, "simple_publish", simple_publish)) {
return CU_get_error();
}
return 0;
}
int main (int argc, char *argv[]) {

View file

@ -22,6 +22,11 @@ reg_sendregister=1
publish=0
dial_escape_plus=0
[friend_0]
url="Paupoche" <sip:pauline@sip.example.org>
pol=accept
subscribe=0
[rtp]
audio_rtp_port=8070

View file

@ -22,6 +22,11 @@ reg_sendregister=1
publish=0
dial_escape_plus=0
#[friend_0]
#url="Mariette" <sip:marie@sip.example.org>
#pol=accept
#subscribe=0
[rtp]
audio_rtp_port=8090
video_rtp_port=8092