Commit 36e445f9 authored by Simon Morlat's avatar Simon Morlat
Browse files

generic subscribe notify api in progress

parent bcbe504b
......@@ -123,7 +123,7 @@ static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to);
static void linphonec_display_something (LinphoneCore * lc, const char *something);
static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
static void linphonec_display_warning (LinphoneCore * lc, const char *something);
static void linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event);
static void linphonec_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState new_call_state);
static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid);
static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
......@@ -281,13 +281,14 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern
* Linphone core callback
*/
static void
linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event)
linphonec_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState new_call_state)
{
if(!strcmp(event,"refer"))
{
linphonec_out("The distand endpoint %s of call %li has been transfered, you can safely close the call.\n",
from,(long)linphone_call_get_user_pointer (call));
char *remote=linphone_call_get_remote_address_as_string(call);
if (new_call_state==LinphoneCallConnected){
linphonec_out("The distant endpoint %s of call %li has been transfered, you can safely close the call.\n",
remote,(long)linphone_call_get_user_pointer (call));
}
ms_free(remote);
}
......@@ -638,7 +639,7 @@ main (int argc, char *argv[]) {
linphonec_vtable.text_received=linphonec_text_received;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
linphonec_vtable.refer_received=linphonec_display_refer;
linphonec_vtable.notify_recv=linphonec_notify_received;
linphonec_vtable.transfer_state_changed=linphonec_transfer_state_changed;
linphonec_vtable.call_encryption_changed=linphonec_call_encryption_changed;
if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
......
......@@ -46,6 +46,7 @@ liblinphone_la_SOURCES=\
conference.c \
message_storage.c \
info.c \
event.c \
$(GITVERSION_FILE)
if BUILD_UPNP
......@@ -63,7 +64,8 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \
bellesip_sal/sal_op_presence.c \
bellesip_sal/sal_op_publish.c \
bellesip_sal/sal_op_call_transfer.c \
bellesip_sal/sal_op_info.c
bellesip_sal/sal_op_info.c \
bellesip_sal/sal_op_events.c
else
liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\
sal_eXosip2_sdp.c \
......
......@@ -141,6 +141,7 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev
belle_sip_header_from_t* from_header;
belle_sip_header_to_t* to;
belle_sip_response_t* resp;
belle_sip_header_t *evh;
from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
......@@ -150,10 +151,13 @@ static void process_request_event(void *sal, const belle_sip_request_event_t *ev
op=sal_op_new((Sal*)sal);
op->dir=SalOpDirIncoming;
sal_op_call_fill_cbs(op);
} else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) {
} else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0 && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) {
op=sal_op_new((Sal*)sal);
op->dir=SalOpDirIncoming;
sal_op_presence_fill_cbs(op);
if (strncmp(belle_sip_header_get_unparsed_value(evh),"presence",strlen("presence"))==0){
sal_op_presence_fill_cbs(op);
}else
sal_op_subscribe_fill_cbs(op);
} else if (strcmp("MESSAGE",belle_sip_request_get_method(req))==0) {
op=sal_op_new((Sal*)sal);
op->dir=SalOpDirIncoming;
......@@ -259,7 +263,6 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
}
if (sal_op_get_contact(op)){
if (received!=NULL || rport>0) {
contact_address = BELLE_SIP_HEADER_ADDRESS(sal_address_clone(sal_op_get_contact_address(op)));
contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_address));
if (received && strcmp(received,belle_sip_uri_get_host(contact_uri))!=0) {
......@@ -302,30 +305,28 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
/*handle authorization*/
switch (response_code) {
case 200: {
break;
}
case 401:
case 407:{
/*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/
if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) {
/*only bye are completed*/
belle_sip_message("Op is in state terminating, nothing else to do ");
} else {
if (op->pending_auth_transaction){
belle_sip_object_unref(op->pending_auth_transaction);
op->pending_auth_transaction=NULL;
case 200: {
break;
}
case 401:
case 407:{
/*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/
if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) {
/*only bye are completed*/
belle_sip_message("Op is in state terminating, nothing else to do ");
} else {
if (op->pending_auth_transaction){
belle_sip_object_unref(op->pending_auth_transaction);
op->pending_auth_transaction=NULL;
}
op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
sal_process_authentication(op);
return;
}
op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
sal_process_authentication(op);
return;
}
}
}
op->callbacks.process_response_event(op,event);
} else {
ms_error("Unhandled event response [%p]",event);
}
......@@ -444,10 +445,14 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub;
if (ctx->callbacks.notify==NULL)
ctx->callbacks.notify=(SalOnNotify)unimplemented_stub;
if (ctx->callbacks.notify_presence==NULL)
ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;
if (ctx->callbacks.subscribe_received==NULL)
ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub;
if (ctx->callbacks.subscribe_closed==NULL)
ctx->callbacks.subscribe_closed=(SalOnSubscribeClosed)unimplemented_stub;
if (ctx->callbacks.notify_presence==NULL)
ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;
if (ctx->callbacks.subscribe_presence_received==NULL)
ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub;
if (ctx->callbacks.text_received==NULL)
ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
if (ctx->callbacks.ping_reply==NULL)
......
......@@ -66,7 +66,8 @@ typedef enum SalOpType {
SalOpMessage,
SalOpPresence,
SalOpPublish,
SalOpInfo
SalOpInfo,
SalOpSubscribe
}SalOpType_t;
const char* sal_op_type_to_string(const SalOpType_t type);
......@@ -127,6 +128,8 @@ void sal_op_message_fill_cbs(SalOp*op);
/*info*/
void sal_op_info_fill_cbs(SalOp*op);
void sal_op_subscribe_fill_cbs(SalOp*op);
/*call transfer*/
void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event);
void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event);
......@@ -140,4 +143,9 @@ belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_reque
void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming);
void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body);
bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody);
SalReason sal_reason_to_sip_code(SalReason r);
#endif /* SAL_IMPL_H_ */
/*
linphone
Copyright (C) 2012 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sal_impl.h"
static void subscribe_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
ms_error("subscribe_process_io_error not implemented yet");
}
static void subscribe_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
SalOp* op= (SalOp*)ctx;
if (op->dialog) {
sal_op_unref(op);
op->dialog=NULL;
}
}
SalSubscribeStatus get_subscription_state(belle_sip_message_t *msg){
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(msg,belle_sip_header_subscription_state_t);
SalSubscribeStatus sss=SalSubscribeNone;
if (subscription_state_header){
if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED)==0)
sss=SalSubscribeTerminated;
else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_PENDING)==0)
sss=SalSubscribePending;
else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE)==0)
sss=SalSubscribeActive;
}
return sss;
}
static void subscribe_response_event(void *op_base, const belle_sip_response_event_t *event){
SalOp* op = (SalOp*)op_base;
belle_sip_dialog_state_t dialog_state;
belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
belle_sip_response_t* response=belle_sip_response_event_get_response(event);
belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
int code = belle_sip_response_get_status_code(response);
char reason[256]={0};
SalError error=SalErrorUnknown;
SalReason sr=SalReasonUnknown;
belle_sip_header_expires_t* expires;
SalSubscribeStatus sss=get_subscription_state(BELLE_SIP_MESSAGE(response));
if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) {
ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr));
op->base.root->callbacks.subscribe_response(op,SalSubscribeTerminated,error,sr);
return;
}
set_or_update_dialog(op_base,belle_sip_response_event_get_dialog(event));
if (!op->dialog) {
ms_message("subscribe op [%p] receive out of dialog answer [%i]",op,code);
return;
}
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL:
case BELLE_SIP_DIALOG_EARLY: {
ms_error("subscribe op [%p] receive an unexpected answer [%i]",op,code);
break;
}
case BELLE_SIP_DIALOG_CONFIRMED: {
if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0) {
expires=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t);
if(op->refresher) {
belle_sip_refresher_stop(op->refresher);
belle_sip_object_unref(op->refresher);
op->refresher=NULL;
}
if (expires>0){
op->refresher=belle_sip_client_transaction_create_refresher(client_transaction);
}
op->base.root->callbacks.subscribe_response(op,sss,SalErrorNone,SalReasonUnknown);
}
break;
}
case BELLE_SIP_DIALOG_TERMINATED:
if (op->refresher) {
belle_sip_refresher_stop(op->refresher);
belle_sip_object_unref(op->refresher);
op->refresher=NULL;
}
break;
default: {
ms_error("subscribe op [%p] receive answer [%i] not implemented",op,code);
}
/* no break */
}
}
static void subscribe_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
ms_message("subscribe_process_timeout not implemented yet");
}
static void subscribe_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
ms_message("subscribe_process_transaction_terminated not implemented yet");
}
static void subscribe_process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_dialog_state_t dialog_state;
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t);
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
belle_sip_header_t *event_header;
SalBody body;
SalSubscribeStatus sub_state;
belle_sip_response_t* resp;
const char *eventname=NULL;
belle_sip_object_ref(server_transaction);
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
op->pending_server_trans=server_transaction;
event_header=belle_sip_message_get_header((belle_sip_message_t*)req,"Event");
eventname=belle_sip_header_get_unparsed_value(event_header);
sal_op_get_body(op,(belle_sip_message_t*)req,&body);
if (eventname==NULL){
ms_warning("No event header in incoming SUBSCRIBE.");
resp=sal_op_create_response_from_request(op,req,400);
belle_sip_server_transaction_send_response(server_transaction,resp);
return;
}
if (!op->dialog) {
op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction));
belle_sip_dialog_set_application_data(op->dialog,op);
sal_op_ref(op);
ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
}
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL: {
op->base.root->callbacks.subscribe_received(op,eventname,body.type ? &body : NULL);
break;
}
case BELLE_SIP_DIALOG_EARLY:
ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",belle_sip_request_get_method(req),op->dialog);
break;
case BELLE_SIP_DIALOG_CONFIRMED:
if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
sub_state=SalSubscribeTerminated;
ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else
sub_state=SalSubscribeActive;
op->base.root->callbacks.notify(op,sub_state,eventname,&body);
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
} else if (strcmp("SUBSCRIBE",belle_sip_request_get_method(req))==0) {
/*either a refresh of an unsubscribe*/
if (expires && belle_sip_header_expires_get_expires(expires)>0) {
} else if(expires) {
ms_message("Unsubscribe received from [%s]",sal_op_get_from(op));
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
op->base.root->callbacks.subscribe_closed(op);
}
}
break;
default: {
ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
}
}
}
void sal_op_subscribe_fill_cbs(SalOp*op) {
op->callbacks.process_io_error=subscribe_process_io_error;
op->callbacks.process_response_event=subscribe_response_event;
op->callbacks.process_timeout=subscribe_process_timeout;
op->callbacks.process_transaction_terminated=subscribe_process_transaction_terminated;
op->callbacks.process_request_event=subscribe_process_request_event;
op->callbacks.process_dialog_terminated=subscribe_process_dialog_terminated;
op->type=SalOpSubscribe;
}
static int set_event_name(SalOp *op, belle_sip_message_t *msg){
belle_sip_transaction_t *last_transaction;
belle_sip_request_t *req;
belle_sip_header_t *event;
if (!op->dialog) return -1;
last_transaction=belle_sip_dialog_get_last_transaction(op->dialog);
if (!last_transaction) return -1;
req=belle_sip_transaction_get_request(last_transaction);
event=belle_sip_message_get_header((belle_sip_message_t*)req,"Event");
if (!event){
ms_error("No event header in last request.");
return -1;
}
belle_sip_message_add_header(msg,event);
return 0;
}
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){
belle_sip_request_t *req=NULL;
if (from)
sal_op_set_from(op,from);
if (to)
sal_op_set_to(op,to);
if (!op->dialog){
sal_op_subscribe_fill_cbs(op);
/*???sal_exosip_fix_route(op); make sure to ha ;lr*/
req=sal_op_build_request(op,"SUBSCRIBE");
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname));
}else{
belle_sip_transaction_t *last=belle_sip_dialog_get_last_transaction(op->dialog);
belle_sip_message_t *msg=BELLE_SIP_MESSAGE(belle_sip_transaction_get_request(last));
req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE");
if (expires==-1){
belle_sip_header_expires_t *eh=belle_sip_message_get_header_by_type(msg,belle_sip_header_expires_t);
expires=belle_sip_header_expires_get_expires(eh);
}
set_event_name(op,(belle_sip_message_t*)req);
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
sal_op_add_body(op,(belle_sip_message_t*)req,body);
return sal_op_send_request(op,req);
}
int sal_unsubscribe(SalOp *op){
belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE"):NULL; /*cannot create request if dialog not set yet*/
if (!req) {
ms_error("Cannot unsubscribe to [%s]",sal_op_get_to(op));
return -1;
}
if (op->refresher)
belle_sip_refresher_stop(op->refresher);
set_event_name(op,(belle_sip_message_t*)req);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(0)));
return sal_op_send_request(op,req);
}
int sal_subscribe_accept(SalOp *op){
belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans));
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
belle_sip_response_t* resp = sal_op_create_response_from_request(op,req,200);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires));
belle_sip_server_transaction_send_response(op->pending_server_trans,resp);
return 0;
}
int sal_subscribe_decline(SalOp *op, SalReason reason){
belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),
sal_reason_to_sip_code(reason));
belle_sip_server_transaction_send_response(op->pending_server_trans,resp);
return 0;
}
int sal_notify(SalOp *op, const SalBody *body){
belle_sip_request_t* notify;
if (!op->dialog) return -1;
notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY");
if (set_event_name(op,(belle_sip_message_t*)notify)==-1){
belle_sip_object_unref(notify);
return -1;
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)));
sal_op_add_body(op,(belle_sip_message_t*)notify, body);
return sal_op_send_request(op,notify);
}
int sal_notify_close(SalOp *op){
belle_sip_request_t* notify;
if (!op->dialog) return -1;
notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY");
set_event_name(op,(belle_sip_message_t*)notify);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1)));
return sal_op_send_request(op,notify);
}
......@@ -256,56 +256,93 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
return _sal_op_send_request_with_contact(op, request,need_contact);
}
void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) {
switch(code) {
case 400:
*sal_err=SalErrorUnknown;
SalReason sal_reason_to_sip_code(SalReason r){
int ret=500;
switch(r){
case SalReasonUnknown:
ret=400;
break;
case 403:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonForbidden;
case SalReasonBusy:
ret=486;
break;
case 404:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonNotFound;
case SalReasonDeclined:
ret=603;
break;
case 415:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonMedia;
case SalReasonDoNotDisturb:
ret=600;
break;
case 422:
ms_error ("422 not implemented yet");;
case SalReasonForbidden:
ret=403;
break;
case 480:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonTemporarilyUnavailable;
case SalReasonMedia:
ret=415;
break;
case 486:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonBusy;
case SalReasonNotFound:
ret=404;
break;
case 487:
case SalReasonRedirect:
ret=302;
break;
case 503:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonServiceUnavailable;
case SalReasonTemporarilyUnavailable:
ret=480;
break;
case 600:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonDoNotDisturb;
case SalReasonServiceUnavailable:
ret=503;
break;
case 603:
}
return ret;
}
void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) {
switch(code) {
case 400:
*sal_err=SalErrorUnknown;
break;
case 403:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonForbidden;
break;
case 404:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonNotFound;
break;
case 415:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonMedia;
break;
case 422:
ms_error ("422 not implemented yet");;
break;
case 480:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonTemporarilyUnavailable;
break;
case 486:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonBusy;
break;
case 487:
break;
case 600:
*sal_err=SalErrorFailure;
*sal_reason=SalReasonDoNotDisturb;
break;