]> sjero.net Git - linphone/commitdiff
- fix text_received() callback so that it can work without date header.
authorSimon Morlat <simon.morlat@linphone.org>
Wed, 6 Feb 2013 21:27:58 +0000 (22:27 +0100)
committerSimon Morlat <simon.morlat@linphone.org>
Wed, 6 Feb 2013 21:29:13 +0000 (22:29 +0100)
- add api to add custom header (work in progress)
- add accessors to call logs and hide the structure into private.h

15 files changed:
console/commands.c
coreapi/callbacks.c
coreapi/chat.c
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/linphonecore.h
coreapi/private.h
coreapi/sal.c
coreapi/sal.h
coreapi/sal_eXosip2.c
coreapi/sal_eXosip2.h
coreapi/sal_eXosip2_presence.c
gtk/calllogs.c
gtk/incall_view.c
mediastreamer2

index 3ec2ed65b2a09266e6f716d50f0f79e3ae4b0498..a91c58c447cc5ba706d83e93308c9d37e47005d6 100644 (file)
@@ -1965,7 +1965,7 @@ static int lpc_cmd_duration(LinphoneCore *lc, char *args){
        for(;elem!=NULL;elem=elem->next){
                if (elem->next==NULL){
                        cl=(LinphoneCallLog*)elem->data;
-                       linphonec_out("%i seconds\n",cl->duration);
+                       linphonec_out("%i seconds\n",linphone_call_log_get_duration(cl));
                }
        }
        return 1;
index 552d34804a67cc6d2ffd4cf549ed2740c7950e76..6bdecc4b584885e271420efa581301a432a0c0ae 100644 (file)
@@ -842,8 +842,8 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){
 }
 
 
-static void text_received(Sal *sal, const SalMessage *msg){
-       LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
+static void text_received(SalOp *op, const SalMessage *msg){
+       LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
        if (is_duplicate_msg(lc,msg->message_id)==FALSE){
                linphone_core_message_received(lc,msg);
        }
index c502efa9f0f1cc51dd6d6bf071fb9521dcf647e8..29af16eecd38b61b0db10e07cc05678cf33a387c 100644 (file)
@@ -160,13 +160,6 @@ LinphoneChatMessage* linphone_chat_room_create_message(const LinphoneChatRoom *c
        return msg;
 }
 
-void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
-       if (msg->message) ms_free(msg->message);
-       if (msg->external_body_url) ms_free(msg->external_body_url);
-       if (msg->from) linphone_address_destroy(msg->from);
-       ms_free(msg);
-}
-
 void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud) {
        msg->cb=status_cb;
        msg->cb_ud=ud;
@@ -231,6 +224,15 @@ time_t linphone_chat_message_get_time(const LinphoneChatMessage* message) {
 const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) {
        return message->message;
 }
+
+void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value){
+       message->custom_headers=sal_custom_header_append(message->custom_headers,header_name,header_value);
+}
+
+const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name){
+       return sal_custom_header_find(message->custom_headers,header_name);
+}
+
 LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) {
        /*struct _LinphoneChatMessage {
         char* message;
@@ -250,3 +252,13 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg)
        if (msg->from) new_message->from=linphone_address_clone(msg->from);
        return new_message;
 }
+
+void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
+       if (msg->message) ms_free(msg->message);
+       if (msg->external_body_url) ms_free(msg->external_body_url);
+       if (msg->from) linphone_address_destroy(msg->from);
+       if (msg->custom_headers) sal_custom_header_free(msg->custom_headers);
+       ms_free(msg);
+}
+
+
index 36b8c69183f9a4b7a399ca502af302e096971eab..27354f61c8a4d625182e9c7b587f05699a76d0da 100644 (file)
@@ -472,6 +472,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
        linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
        linphone_call_init_common(call,from,to);
        _linphone_call_params_copy(&call->params,params);
+       sal_op_set_custom_header(call->op,call->params.custom_headers);
+       
        if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
                call->ice_session = ice_session_new();
                ice_session_set_role(call->ice_session, IR_Controlling);
@@ -733,9 +735,7 @@ static void linphone_call_destroy(LinphoneCall *obj)
        if (obj->auth_token) {
                ms_free(obj->auth_token);
        }
-       if (obj->params.record_file)
-               ms_free(obj->params.record_file);
-
+       linphone_call_params_uninit(&obj->params);
        ms_free(obj);
 }
 
@@ -810,6 +810,7 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
                                        cp->low_bandwidth=TRUE;
                                }
                        }
+                       cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
                        return cp;
                }
        }
@@ -963,6 +964,18 @@ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
 #endif
 }
 
+#ifdef VIDEO_ENABLED
+/**
+ * Request remote side to send us a Video Fast Update.
+**/
+void linphone_call_send_vfu_request(LinphoneCall *call)
+{
+       if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
+               sal_call_send_vfu_request(call->op);
+}
+#endif
+
+
 /**
  * Take a photo of currently received video and write it into a jpeg file.
 **/
@@ -1038,10 +1051,16 @@ bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
        return cp->has_video;
 }
 
+/**
+ * Returns kind of media encryption selected for the call.
+**/
 enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
        return cp->media_encryption;
 }
 
+/**
+ * Set requested media encryption for a call.
+**/
 void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
        cp->media_encryption = e;
 }
@@ -1054,6 +1073,9 @@ void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, boo
        cp->real_early_media=enabled;
 }
 
+/**
+ * Indicates whether sending of early media was enabled.
+**/
 bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
        return cp->real_early_media;
 }
@@ -1073,25 +1095,25 @@ void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int
        cp->audio_bw=bandwidth;
 }
 
-#ifdef VIDEO_ENABLED
-/**
- * Request remote side to send us a Video Fast Update.
-**/
-void linphone_call_send_vfu_request(LinphoneCall *call)
-{
-       if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
-               sal_call_send_vfu_request(call->op);
+void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
+       params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
 }
-#endif
 
+const char *linphone_call_params_get_custom_header(LinphoneCallParams *params, const char *header_name){
+       return sal_custom_header_find(params->custom_headers,header_name);
+}
 
 void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
        memcpy(ncp,cp,sizeof(LinphoneCallParams));
        if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
+       /*
+        * The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
+        */
+       if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
 }
 
 /**
- *
+ * Copy existing LinphoneCallParams to a new LinphoneCallParams object.
 **/
 LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
        LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
@@ -1099,14 +1121,20 @@ LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
        return ncp;
 }
 
+void linphone_call_params_uninit(LinphoneCallParams *p){
+       if (p->record_file) ms_free(p->record_file);
+       if (p->custom_headers) sal_custom_header_free(p->custom_headers);
+}
+
 /**
- *
+ * Destroy LinphoneCallParams.
 **/
 void linphone_call_params_destroy(LinphoneCallParams *p){
-       if (p->record_file) ms_free(p->record_file);
+       linphone_call_params_uninit(p);
        ms_free(p);
 }
 
+
 /**
  * @}
 **/
index 76ccc1f051ca6c074810e06ea756b75e43bd4c82..4c58225902c8a8c37d4c5f47d3d8bbcaa437a51b 100644 (file)
@@ -203,8 +203,8 @@ static void call_logs_read_from_config_file(LinphoneCore *lc){
                        if (tmp) cl->refkey=ms_strdup(tmp);
                        cl->quality=lp_config_get_float(cfg,logsection,"quality",-1);
                        cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0);
-                       cl->call_id=lp_config_get_string(cfg,logsection,"call_id",NULL);
-                       if(cl->call_id) cl->call_id=ms_strdup(cl->call_id);
+                       tmp=lp_config_get_string(cfg,logsection,"call_id",NULL);
+                       if (tmp) cl->call_id=ms_strdup(tmp);
                        lc->call_logs=ms_list_append(lc->call_logs,cl);
                }else break;
        }
@@ -270,10 +270,16 @@ const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl)
        return &cl->remote_stats;
 }
 
+/**
+ * Assign a user pointer to the call log.
+**/
 void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up){
        cl->user_pointer=up;
 }
 
+/**
+ * Returns the user pointer associated with the call log.
+**/
 void *linphone_call_log_get_user_pointer(const LinphoneCallLog *cl){
        return cl->user_pointer;
 }
@@ -306,13 +312,62 @@ const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){
        return cl->refkey;
 }
 
+/**
+ * Returns origin (ie from) address of the call.
+**/
+LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl){
+       return cl->from;
+}
+
+/**
+ * Returns destination address (ie to) of the call.
+**/
+LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl){
+       return cl->to;
+}
+
+/**
+ * Returns the direction of the call.
+**/
+LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl){
+       return cl->dir;
+}
+
+/**
+ * Returns the status of the call.
+**/
+LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl){
+       return cl->status;
+}
+
+/**
+ * Returns the start date of the call, expressed as a POSIX time_t.
+**/
+time_t linphone_call_log_get_start_date(LinphoneCallLog *cl){
+       return cl->start_date_time;
+}
+
+/**
+ * Returns duration of the call.
+**/
+int linphone_call_log_get_duration(LinphoneCallLog *cl){
+       return cl->duration;
+}
+
+/**
+ * Returns overall quality indication of the call.
+**/
+float linphone_call_log_get_quality(LinphoneCallLog *cl){
+       return cl->quality;
+}
+
 /** @} */
 
 void linphone_call_log_destroy(LinphoneCallLog *cl){
        if (cl->from!=NULL) linphone_address_destroy(cl->from);
        if (cl->to!=NULL) linphone_address_destroy(cl->to);
        if (cl->refkey!=NULL) ms_free(cl->refkey);
-       if (cl->call_id) ms_free((void*)cl->call_id);
+       if (cl->call_id) ms_free(cl->call_id);
        ms_free(cl);
 }
 
index 6228861de57710dd8d3282fea39a6083c310ce66..08c4f89ee26eb67aedabcb0fb3e432bde19c06fd 100644 (file)
@@ -141,24 +141,7 @@ typedef enum _LinphoneCallStatus {
  * @ingroup call_logs
  *
 **/
-typedef struct _LinphoneCallLog{
-       LinphoneCallDir dir; /**< The direction of the call*/
-       LinphoneCallStatus status; /**< The status of the call*/
-       LinphoneAddress *from; /**<Originator of the call as a LinphoneAddress object*/
-       LinphoneAddress *to; /**<Destination of the call as a LinphoneAddress object*/
-       char start_date[128]; /**<Human readable string containing the start date*/
-       int duration; /**<Duration of the call in seconds*/
-       char *refkey;
-       void *user_pointer;
-       rtp_stats_t local_stats;
-       rtp_stats_t remote_stats;
-       float quality;
-    int video_enabled;
-       struct _LinphoneCore *lc;
-       time_t start_date_time; /**Start date of the call in seconds as expressed in a time_t */
-       const char* call_id; /**unique id of a call*/
-} LinphoneCallLog;
-
+typedef struct _LinphoneCallLog LinphoneCallLog;
 
 /**
  * Enum describing type of media encryption types.
@@ -175,6 +158,13 @@ enum LinphoneMediaEncryption {
 typedef enum LinphoneMediaEncryption LinphoneMediaEncryption;
 
 /*public: */
+LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl);
+LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl);
+LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl);
+LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl);
+time_t linphone_call_log_get_start_date(LinphoneCallLog *cl);
+int linphone_call_log_get_duration(LinphoneCallLog *cl);
+float linphone_call_log_get_quality(LinphoneCallLog *cl);
 void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up);
 void *linphone_call_log_get_user_pointer(const LinphoneCallLog *cl);
 void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey);
@@ -208,6 +198,8 @@ bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp);
 void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled);
 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path);
 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp);
+void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value);
+const char *linphone_call_params_get_custom_header(LinphoneCallParams *params, const char *header_name);
 /**
  * Enum describing failure reasons.
  * @ingroup initializing
index 4048be98ace0d18aaf873174a0e7f3f872889ca9..b98995fa6cae873d32ced58ebdd00a01299e859f 100644 (file)
@@ -81,17 +81,36 @@ struct _LinphoneCallParams{
        int down_ptime;
        int up_ptime;
        char *record_file;
+       SalCustomHeader *custom_headers;
        bool_t has_video;
        bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
        bool_t in_conference; /*in conference mode */
        bool_t pad;
        bool_t low_bandwidth;
 };
-    
+
+struct _LinphoneCallLog{
+       struct _LinphoneCore *lc;
+       LinphoneCallDir dir; /**< The direction of the call*/
+       LinphoneCallStatus status; /**< The status of the call*/
+       LinphoneAddress *from; /**<Originator of the call as a LinphoneAddress object*/
+       LinphoneAddress *to; /**<Destination of the call as a LinphoneAddress object*/
+       char start_date[128]; /**<Human readable string containing the start date*/
+       int duration; /**<Duration of the call in seconds*/
+       char *refkey;
+       void *user_pointer;
+       rtp_stats_t local_stats;
+       rtp_stats_t remote_stats;
+       float quality;
+       time_t start_date_time; /**Start date of the call in seconds as expressed in a time_t */
+       char* call_id; /**unique id of a call*/
+       bool_t video_enabled;
+};
+
 typedef struct _CallCallbackObj
 {
-    LinphoneCallCbFunc _func;
-    void * _user_data;
+       LinphoneCallCbFunc _func;
+       void * _user_data;
 }CallCallbackObj;
 
 static const int linphone_call_magic=0x3343;
@@ -105,6 +124,7 @@ struct _LinphoneChatMessage {
        char* external_body_url;
        LinphoneAddress* from;
        time_t time;
+       SalCustomHeader *custom_headers;
 };
 
 typedef struct StunCandidate{
@@ -664,6 +684,7 @@ void call_logs_write_to_config_file(LinphoneCore *lc);
 int linphone_core_get_edge_bw(LinphoneCore *lc);
 int linphone_core_get_edge_ptime(LinphoneCore *lc);
 void _linphone_call_params_copy(LinphoneCallParams *params, const LinphoneCallParams *refparams);
+void linphone_call_params_uninit(LinphoneCallParams *params);
 
 int linphone_upnp_init(LinphoneCore *lc);
 void linphone_upnp_destroy(LinphoneCore *lc);
index d91be1cb6a891ce1049ecd6768520cd316838672..e988a141bb9b5af1c79bdb8d5d819563679e9a6c 100644 (file)
@@ -348,6 +348,8 @@ void __sal_op_free(SalOp *op){
                sal_media_description_unref(b->remote_media);
        if (b->call_id)
                ms_free(b->call_id);
+       if (b->custom_headers)
+               sal_custom_header_free(b->custom_headers);
        ms_free(op);
 }
 
@@ -372,3 +374,60 @@ void sal_auth_info_delete(const SalAuthInfo* auth_info) {
        ms_free((void*)auth_info);
 }
 
+SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){
+       SalCustomHeader *h=ms_new0(SalCustomHeader,1);
+       h->header_name=ms_strdup(name);
+       h->header_value=ms_strdup(value);
+       h->node.data=h;
+       return (SalCustomHeader*)ms_list_append_link((MSList*)ch,(MSList*)h);
+}
+
+const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){
+       const MSList *it;
+       for (it=(const MSList*)ch;it!=NULL;it=it->next){
+               const SalCustomHeader *itch=(const SalCustomHeader *)it;
+               if (strcasecmp(itch->header_name,name)==0)
+                       return itch->header_value;
+       }
+       return NULL;
+}
+
+static void sal_custom_header_uninit(SalCustomHeader *ch){
+       ms_free(ch->header_name);
+       ms_free(ch->header_value);
+}
+
+void sal_custom_header_free(SalCustomHeader *ch){
+       ms_list_for_each((MSList*)ch,(void (*)(void*))sal_custom_header_uninit);
+       ms_list_free((MSList *)ch);
+}
+
+SalCustomHeader *sal_custom_header_clone(SalCustomHeader *ch){
+       const MSList *it;
+       SalCustomHeader *ret=NULL;
+       for (it=(const MSList*)ch;it!=NULL;it=it->next){
+               const SalCustomHeader *itch=(const SalCustomHeader *)it;
+               ret=sal_custom_header_append(ret,itch->header_name,itch->header_value);
+       }
+       return ret;
+}
+
+const SalCustomHeader *sal_op_get_custom_header(SalOp *op){
+       SalOpBase *b=(SalOpBase *)op;
+       return b->custom_headers;
+}
+
+/*
+ * Warning: this function takes owneship of the custom headers
+ */
+void sal_op_set_custom_header(SalOp *op, SalCustomHeader* ch){
+       SalOpBase *b=(SalOpBase *)op;
+       if (b->custom_headers){
+               sal_custom_header_free(b->custom_headers);
+               b->custom_headers=NULL;
+       }
+       b->custom_headers=ch;
+}
+
+
+
index 46294b6038b86eb32bf0f420958436a729580e6b..26efa81152850f22db507823233acfa435ef529c 100644 (file)
@@ -46,6 +46,10 @@ struct SalAddress;
 
 typedef struct SalAddress SalAddress;
 
+struct SalCustomHeader;
+
+typedef struct SalCustomHeader SalCustomHeader;
+
 typedef enum {
        SalTransportUDP, /*UDP*/
        SalTransportTCP, /*TCP*/
@@ -224,6 +228,7 @@ typedef struct SalOpBase{
        void *user_pointer;
        char* call_id;
        char *remote_contact;
+       SalCustomHeader *custom_headers;
 } SalOpBase;
 
 
@@ -291,7 +296,7 @@ typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason
 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 SalMessage *msg);
+typedef void (*SalOnTextReceived)(SalOp *op, const SalMessage *msg);
 typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status);
 typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event);
 typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state);
@@ -451,6 +456,19 @@ int sal_ping(SalOp *op, const char *from, const char *to);
 /*misc*/
 void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen);
 
+struct SalCustomHeader{
+       MSList node;
+       char *header_name;
+       char *header_value;
+};
+
+SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value);
+const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name);
+void sal_custom_header_free(SalCustomHeader *ch);
+SalCustomHeader *sal_custom_header_clone(SalCustomHeader *ch);
+const SalCustomHeader *sal_op_get_custom_header(SalOp *op);
+void sal_op_set_custom_header(SalOp *op, SalCustomHeader* ch);
+
 
 /*internal API */
 void __sal_op_init(SalOp *b, Sal *sal);
index 91ec04679137e83817efeaeda06d335d8af63fff..1777c0d42cf07c28cecce35cf4cf7b3da0433b9d 100644 (file)
-/*
-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.
-*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sal_eXosip2.h"
-#include "offeranswer.h"
-
-#ifdef ANDROID
-// Necessary to make it linked
-static void for_linker() { eXosip_transport_hook_register(NULL); }
-#endif
-static bool_t call_failure(Sal *sal, eXosip_event_t *ev);
-
-static void text_received(Sal *sal, eXosip_event_t *ev);
-
-static void masquerade_via(osip_message_t *msg, const char *ip, const char *port);
-static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact);
-static void update_contact_from_response(SalOp *op, osip_message_t *response);
-
-void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){
-       void *data;
-       while(!osip_list_eol(l,0)) {
-               data=osip_list_get(l,0);
-               osip_list_remove(l,0);
-               if (data) freefunc(data);
-       }
-}
-
-void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iplen){
-       if (eXosip_guess_localip(address_family,ip,iplen)<0){
-               /*default to something */
-               strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen);
-               ms_error("Could not find default routable ip address !");
-       }
-}
-
-static SalOp * sal_find_call(Sal *sal, int cid){
-       const MSList *elem;
-       SalOp *op;
-       for(elem=sal->calls;elem!=NULL;elem=elem->next){
-               op=(SalOp*)elem->data;
-               if (op->cid==cid) return op;
-       }
-       return NULL;
-}
-
-static void sal_add_call(Sal *sal, SalOp *op){
-       sal->calls=ms_list_append(sal->calls,op);
-}
-
-static void sal_remove_call(Sal *sal, SalOp *op){
-       sal->calls=ms_list_remove(sal->calls, op);
-}
-
-static SalOp * sal_find_register(Sal *sal, int rid){
-       const MSList *elem;
-       SalOp *op;
-       for(elem=sal->registers;elem!=NULL;elem=elem->next){
-               op=(SalOp*)elem->data;
-               if (op->rid==rid) return op;
-       }
-       return NULL;
-}
-
-static void sal_add_register(Sal *sal, SalOp *op){
-       sal->registers=ms_list_append(sal->registers,op);
-}
-
-static void sal_remove_register(Sal *sal, int rid){
-       MSList *elem;
-       SalOp *op;
-       for(elem=sal->registers;elem!=NULL;elem=elem->next){
-               op=(SalOp*)elem->data;
-               if (op->rid==rid) {
-                       sal->registers=ms_list_remove_link(sal->registers,elem);
-                       return;
-               }
-       }
-}
-
-static SalOp * sal_find_other(Sal *sal, osip_message_t *message){
-       const MSList *elem;
-       SalOp *op;
-       osip_call_id_t *callid=osip_message_get_call_id(message);
-       if (callid==NULL) {
-               ms_error("There is no call-id in this message !");
-               return NULL;
-       }
-       for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){
-               op=(SalOp*)elem->data;
-               if (osip_call_id_match(callid,op->call_id)==0) return op;
-       }
-       return NULL;
-}
-
-void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){
-       osip_call_id_t *callid=osip_message_get_call_id(request);
-       if (callid==NULL) {
-               ms_error("There is no call id in the request !");
-               return;
-       }
-       osip_call_id_clone(callid,&op->call_id);
-       sal->other_transactions=ms_list_append(sal->other_transactions,op);
-}
-
-static void sal_remove_other(Sal *sal, SalOp *op){
-       sal->other_transactions=ms_list_remove(sal->other_transactions,op);
-}
-
-
-static void sal_add_pending_auth(Sal *sal, SalOp *op){
-       sal->pending_auths=ms_list_append(sal->pending_auths,op);
-}
-
-
-static void sal_remove_pending_auth(Sal *sal, SalOp *op){
-       sal->pending_auths=ms_list_remove(sal->pending_auths,op);
-}
-
-void sal_exosip_fix_route(SalOp *op){
-       if (sal_op_get_route(op)!=NULL){
-               osip_route_t *rt=NULL;
-               osip_uri_param_t *lr_param=NULL;
-               
-               osip_route_init(&rt);
-               if (osip_route_parse(rt,sal_op_get_route(op))<0){
-                       ms_warning("Bad route  %s!",sal_op_get_route(op));
-                       sal_op_set_route(op,NULL);
-               }else{
-                       /* 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){
-                               char *tmproute;
-                               osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL);
-                               osip_route_to_str(rt,&tmproute);
-                               sal_op_set_route(op,tmproute);
-                               osip_free(tmproute);
-                       }
-               }
-               osip_route_free(rt);
-       }
-}
-
-SalOp * sal_op_new(Sal *sal){
-       SalOp *op=ms_new0(SalOp,1);
-       __sal_op_init(op,sal);
-       op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1;
-       op->result=NULL;
-       op->supports_session_timers=FALSE;
-       op->sdp_offering=TRUE;
-       op->pending_auth=NULL;
-       op->sdp_answer=NULL;
-       op->reinvite=FALSE;
-       op->call_id=NULL;
-       op->replaces=NULL;
-       op->referred_by=NULL;
-       op->masquerade_via=FALSE;
-       op->auto_answer_asked=FALSE;
-       op->auth_info=NULL;
-       op->terminated=FALSE;
-       return op;
-}
-
-bool_t sal_call_autoanswer_asked(SalOp *op)
-{
-       return op->auto_answer_asked;
-}
-
-void sal_op_release(SalOp *op){
-       if (op->sdp_answer)
-               sdp_message_free(op->sdp_answer);
-       if (op->pending_auth)
-               eXosip_event_free(op->pending_auth);
-       if (op->rid!=-1){
-               sal_remove_register(op->base.root,op->rid);
-               eXosip_register_remove(op->rid);
-       }
-       if (op->cid!=-1){
-               ms_message("Cleaning cid %i",op->cid);
-               sal_remove_call(op->base.root,op);
-       }
-       if (op->sid!=-1){
-               sal_remove_out_subscribe(op->base.root,op);
-       }
-       if (op->nid!=-1){
-               sal_remove_in_subscribe(op->base.root,op);
-               if (op->call_id)
-                       osip_call_id_free(op->call_id);
-               op->call_id=NULL;
-       }
-       if (op->pending_auth){
-               sal_remove_pending_auth(op->base.root,op);
-       }
-       if (op->result)
-               sal_media_description_unref(op->result);
-       if (op->call_id){
-               sal_remove_other(op->base.root,op);
-               osip_call_id_free(op->call_id);
-       }
-       if (op->replaces){
-               ms_free(op->replaces);
-       }
-       if (op->referred_by){
-               ms_free(op->referred_by);
-       }
-       if (op->auth_info) {
-               sal_auth_info_delete(op->auth_info);
-       }
-       __sal_op_free(op);
-}
-
-static void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){
-       int ortp_level=ORTP_DEBUG;
-       switch(level){
-               case OSIP_INFO1:
-               case OSIP_INFO2:
-               case OSIP_INFO3:
-               case OSIP_INFO4:
-                       ortp_level=ORTP_MESSAGE;
-                       break;
-               case OSIP_WARNING:
-                       ortp_level=ORTP_WARNING;
-                       break;
-               case OSIP_ERROR:
-               case OSIP_BUG:
-                       ortp_level=ORTP_ERROR;
-                       break;
-               case OSIP_FATAL:
-                       ortp_level=ORTP_FATAL;
-                       break;
-               case END_TRACE_LEVEL:
-                       break;
-       }
-       if (ortp_log_level_enabled(level)){
-               int len=strlen(chfr);
-               char *chfrdup=ortp_strdup(chfr);
-               /*need to remove endline*/
-               if (len>1){
-                       if (chfrdup[len-1]=='\n')
-                               chfrdup[len-1]='\0';
-                       if (chfrdup[len-2]=='\r')
-                               chfrdup[len-2]='\0';
-               }
-               ortp_logv(ortp_level,chfrdup,ap);
-               ortp_free(chfrdup);
-       }
-}
-
-
-Sal * sal_init(){
-       static bool_t firsttime=TRUE;
-       Sal *sal;
-       if (firsttime){
-               osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func);
-               firsttime=FALSE;
-       }
-       eXosip_init();
-       sal=ms_new0(Sal,1);
-       sal->keepalive_period=30;
-       sal->double_reg=TRUE;
-       sal->use_rports=TRUE;
-       sal->use_101=TRUE;
-       sal->reuse_authorization=FALSE;
-       sal->rootCa = 0;
-       sal->verify_server_certs=TRUE;
-       sal->verify_server_cn=TRUE;
-       sal->expire_old_contact=FALSE;
-       sal->add_dates=FALSE;
-       sal->dscp=-1;
-       return sal;
-}
-
-void sal_uninit(Sal* sal){
-       eXosip_quit();
-       if (sal->rootCa)
-               ms_free(sal->rootCa);
-       ms_free(sal);
-}
-
-void sal_set_user_pointer(Sal *sal, void *user_data){
-       sal->up=user_data;
-}
-
-void *sal_get_user_pointer(const Sal *sal){
-       return sal->up;
-}
-
-static void unimplemented_stub(){
-       ms_warning("Unimplemented SAL callback");
-}
-
-void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
-       memcpy(&ctx->callbacks,cbs,sizeof(*cbs));
-       if (ctx->callbacks.call_received==NULL) 
-               ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub;
-       if (ctx->callbacks.call_ringing==NULL) 
-               ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub;
-       if (ctx->callbacks.call_accepted==NULL) 
-               ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub;
-       if (ctx->callbacks.call_failure==NULL) 
-               ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;
-       if (ctx->callbacks.call_terminated==NULL) 
-               ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;
-       if (ctx->callbacks.call_released==NULL)
-               ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub;
-       if (ctx->callbacks.call_updating==NULL) 
-               ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;
-       if (ctx->callbacks.auth_requested==NULL) 
-               ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;
-       if (ctx->callbacks.auth_success==NULL) 
-               ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub;
-       if (ctx->callbacks.register_success==NULL) 
-               ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub;
-       if (ctx->callbacks.register_failure==NULL) 
-               ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub;
-       if (ctx->callbacks.dtmf_received==NULL) 
-               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.text_received==NULL)
-               ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
-       if (ctx->callbacks.ping_reply==NULL)
-               ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;
-}
-
-int sal_unlisten_ports(Sal *ctx){
-       if (ctx->running){
-               eXosip_quit();
-               eXosip_init();
-               ctx->running=FALSE;
-       }
-       return 0;
-}
-
-int sal_reset_transports(Sal *ctx){
-#ifdef HAVE_EXOSIP_RESET_TRANSPORTS
-       if (ctx->running){
-               ms_message("Exosip transports reset.");
-               eXosip_reset_transports();
-       }
-       return 0;
-#else
-       ms_warning("sal_reset_transports() not implemented in this version.");
-       return -1;
-#endif
-}
-
-
-static void set_tls_options(Sal *ctx){
-       if (ctx->rootCa) {
-               eXosip_tls_ctx_t tlsCtx;
-               memset(&tlsCtx, 0, sizeof(tlsCtx));
-               snprintf(tlsCtx.root_ca_cert, sizeof(tlsCtx.client.cert), "%s", ctx->rootCa);
-               eXosip_set_tls_ctx(&tlsCtx);
-       }                       
-#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE
-       eXosip_tls_verify_certificate(ctx->verify_server_certs);
-#endif
-#ifdef HAVE_EXOSIP_TLS_VERIFY_CN
-       eXosip_tls_verify_cn(ctx->verify_server_cn);
-#endif
-}
-
-void sal_set_dscp(Sal *ctx, int dscp){
-       ctx->dscp=dscp;
-#ifdef HAVE_EXOSIP_DSCP
-       if (dscp!=-1)
-               eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp);
-#endif
-}
-
-int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){
-       int err;
-       bool_t ipv6;
-       int proto=IPPROTO_UDP;
-       int keepalive = ctx->keepalive_period;
-
-       ctx->transport = tr;
-       switch (tr) {
-       case SalTransportUDP:
-               proto=IPPROTO_UDP;
-               eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &keepalive);
-               break;
-       case SalTransportTCP:
-       case SalTransportTLS:
-               proto= IPPROTO_TCP;
-               if (!ctx->tcp_tls_keepalive) keepalive=-1;
-               eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive);
-               set_tls_options(ctx);
-               break;
-       default:
-               ms_warning("unexpected proto, using datagram");
-       }
-       /*see if it looks like an IPv6 address*/
-       int use_rports = ctx->use_rports; // Copy char to int to avoid bad alignment
-       eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports);
-       int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment
-       eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101);
-       sal_set_dscp(ctx,ctx->dscp);
-       sal_use_dates(ctx,ctx->add_dates);
-
-       ipv6=strchr(addr,':')!=NULL;
-       eXosip_enable_ipv6(ipv6);
-
-       if (is_secure && tr == SalTransportUDP){
-               ms_fatal("SIP over DTLS is not supported yet.");
-               return -1;
-       }
-       err=eXosip_listen_addr(proto, addr, port, ipv6 ?  PF_INET6 : PF_INET, is_secure);
-       ctx->running=TRUE;
-       return err;
-}
-
-ortp_socket_t sal_get_socket(Sal *ctx){
-#ifdef HAVE_EXOSIP_GET_SOCKET
-       return eXosip_get_socket(IPPROTO_UDP);
-#else
-       ms_warning("Sorry, eXosip does not have eXosip_get_socket() method");
-       return -1;
-#endif
-}
-
-void sal_set_user_agent(Sal *ctx, const char *user_agent){
-       eXosip_set_user_agent(user_agent);
-}
-
-void sal_use_session_timers(Sal *ctx, int expires){
-       ctx->session_expires=expires;
-}
-
-void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){
-       ctx->one_matching_codec=one_matching_codec;
-}
-
-MSList *sal_get_pending_auths(Sal *sal){
-       return ms_list_copy(sal->pending_auths);
-}
-
-void sal_use_double_registrations(Sal *ctx, bool_t enabled){
-       ctx->double_reg=enabled;
-}
-
-void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){
-       ctx->expire_old_contact=enabled;
-}
-
-void sal_use_dates(Sal *ctx, bool_t enabled){
-       ctx->add_dates=enabled;
-#ifdef EXOSIP_OPT_REGISTER_WITH_DATE
-       {
-               int tmp=enabled;
-               eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp);
-       }
-#else
-       if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option.");
-#endif
-}
-
-void sal_use_rport(Sal *ctx, bool_t use_rports){
-       ctx->use_rports=use_rports;
-}
-void sal_use_101(Sal *ctx, bool_t use_101){
-       ctx->use_101=use_101;
-}
-
-void sal_set_root_ca(Sal* ctx, const char* rootCa) {
-       if (ctx->rootCa)
-               ms_free(ctx->rootCa);
-       ctx->rootCa = ms_strdup(rootCa);
-       set_tls_options(ctx);
-}
-
-const char *sal_get_root_ca(Sal* ctx) {
-       return ctx->rootCa;
-}
-
-void sal_verify_server_certificates(Sal *ctx, bool_t verify){
-       ctx->verify_server_certs=verify;
-#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE
-       eXosip_tls_verify_certificate(verify);
-#endif
-}
-
-void sal_verify_server_cn(Sal *ctx, bool_t verify){
-       ctx->verify_server_cn=verify;
-#ifdef HAVE_EXOSIP_TLS_VERIFY_CN
-       eXosip_tls_verify_cn(verify);
-#endif
-}
-
-static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval,SalTransport* transport){
-       osip_via_t *via=NULL;
-       osip_generic_param_t *param=NULL;
-       const char *rport=NULL;
-
-       *rportval=5060;
-       *received=NULL;
-       osip_message_get_via(msg,0,&via);
-       if (!via) {
-               ms_warning("extract_received_rport(): no via.");
-               return -1;
-       }
-
-       *transport = sal_transport_parse(via->protocol);
-       
-       if (via->port && via->port[0]!='\0')
-               *rportval=atoi(via->port);
-       
-       osip_via_param_get_byname(via,"rport",&param);
-       if (param) {
-               rport=param->gvalue;
-               if (rport && rport[0]!='\0') *rportval=atoi(rport);
-               *received=via->host;
-       }
-       param=NULL;
-       osip_via_param_get_byname(via,"received",&param);
-       if (param) *received=param->gvalue;
-
-       if (rport==NULL && *received==NULL){
-               ms_warning("extract_received_rport(): no rport and no received parameters.");
-               return -1;
-       }
-       return 0;
-}
-
-static void set_sdp(osip_message_t *sip,sdp_message_t *msg){
-       int sdplen;
-       char clen[10];
-       char *sdp=NULL;
-       sdp_message_to_str(msg,&sdp);
-       sdplen=strlen(sdp);
-       snprintf(clen,sizeof(clen),"%i",sdplen);
-       osip_message_set_body(sip,sdp,sdplen);
-       osip_message_set_content_type(sip,"application/sdp");
-       osip_message_set_content_length(sip,clen);
-       osip_free(sdp);
-}
-
-static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){
-       sdp_message_t *msg=media_description_to_sdp(desc);
-       if (msg==NULL) {
-               ms_error("Fail to print sdp message !");
-               return;
-       }
-       set_sdp(sip,msg);
-       sdp_message_free(msg);
-}
-
-static void sdp_process(SalOp *h){
-       ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming");
-       if (h->result){
-               sal_media_description_unref(h->result);
-       }
-       h->result=sal_media_description_new();
-       if (h->sdp_offering){   
-               offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result);
-       }else{
-               int i;
-               if (h->sdp_answer){
-                       sdp_message_free(h->sdp_answer);
-               }
-               offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);
-               h->sdp_answer=media_description_to_sdp(h->result);
-               /*once we have generated the SDP answer, we modify the result description for processing by the upper layer.
-                It should contains media parameters constraint from the remote offer, not our response*/
-               strcpy(h->result->addr,h->base.remote_media->addr);
-               h->result->bandwidth=h->base.remote_media->bandwidth;
-               
-               for(i=0;i<h->result->n_active_streams;++i){
-                       strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);
-                       strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);
-                       h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;
-                       h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;
-                       h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;
-                       h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;
-                       if (h->result->streams[i].proto == SalProtoRtpSavp) {
-                               h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];
-                       }
-               }
-       }
-       
-}
-
-int sal_call_is_offerer(const SalOp *h){
-       return h->sdp_offering;
-}
-
-int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){
-       if (desc)
-               sal_media_description_ref(desc);
-       if (h->base.local_media)
-               sal_media_description_unref(h->base.local_media);
-       h->base.local_media=desc;
-       if (h->base.remote_media){
-               /*case of an incoming call where we modify the local capabilities between the time
-                * the call is ringing and it is accepted (for example if you want to accept without video*/
-               /*reset the sdp answer so that it is computed again*/
-               if (h->sdp_answer){
-                       sdp_message_free(h->sdp_answer);
-                       h->sdp_answer=NULL;
-               }
-       }
-       return 0;
-}
-
-int sal_call(SalOp *h, const char *from, const char *to){
-       int err;
-       const char *route;
-       osip_message_t *invite=NULL;
-       osip_call_id_t *callid;
-       sal_op_set_from(h,from);
-       sal_op_set_to(h,to);
-       sal_exosip_fix_route(h);
-       
-       h->terminated = FALSE;
-
-       route = sal_op_get_route(h);
-       err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call");
-       if (err!=0){
-               ms_error("Could not create call. Error %d (from=%s to=%s route=%s)",
-                               err, from, to, route);
-               return -1;
-       }
-       osip_message_set_allow(invite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
-       if (h->base.contact){
-               _osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free);
-               osip_message_set_contact(invite,h->base.contact);
-       }
-       if (h->base.root->session_expires!=0){
-               osip_message_set_header(invite, "Session-expires", "200");
-               osip_message_set_supported(invite, "timer");
-       }
-       if (h->base.local_media){
-               h->sdp_offering=TRUE;
-               set_sdp_from_desc(invite,h->base.local_media);
-       }else h->sdp_offering=FALSE;
-       if (h->replaces){
-               osip_message_set_header(invite,"Replaces",h->replaces);
-               if (h->referred_by)
-                       osip_message_set_header(invite,"Referred-By",h->referred_by);
-       }
-       
-       eXosip_lock();
-       err=eXosip_call_send_initial_invite(invite);
-       eXosip_unlock();
-       h->cid=err;
-       if (err<0){
-               ms_error("Fail to send invite ! Error code %d", err);
-               return -1;
-       }else{
-               char *tmp=NULL;
-               callid=osip_message_get_call_id(invite);
-               osip_call_id_to_str(callid,&tmp);
-               h->base.call_id=ms_strdup(tmp);
-               osip_free(tmp);
-               sal_add_call(h->base.root,h);
-       }
-       return 0;
-}
-
-int sal_call_notify_ringing(SalOp *h, bool_t early_media){
-       osip_message_t *msg;
-       
-       /*if early media send also 180 and 183 */
-       if (early_media){
-               msg=NULL;
-               eXosip_lock();
-               eXosip_call_build_answer(h->tid,183,&msg);
-               if (msg){
-                       sdp_process(h);
-                       if (h->sdp_answer){
-                               set_sdp(msg,h->sdp_answer);
-                               sdp_message_free(h->sdp_answer);
-                               h->sdp_answer=NULL;
-                       }
-                       eXosip_call_send_answer(h->tid,183,msg);
-               }
-               eXosip_unlock();
-       }else{
-               eXosip_lock();
-               eXosip_call_send_answer(h->tid,180,NULL);
-               eXosip_unlock();
-       }
-       return 0;
-}
-
-int sal_call_accept(SalOp * h){
-       osip_message_t *msg;
-       const char *contact=sal_op_get_contact(h);
-       /* sends a 200 OK */
-       int err=eXosip_call_build_answer(h->tid,200,&msg);
-       if (err<0 || msg==NULL){
-               ms_error("Fail to build answer for call: err=%i",err);
-               return -1;
-       }
-       if (h->base.root->session_expires!=0){
-               if (h->supports_session_timers) osip_message_set_supported(msg, "timer");
-       }
-
-       if (contact) {
-               _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
-               osip_message_set_contact(msg,contact);
-       }
-       
-       if (h->base.local_media){
-               /*this is the case where we received an invite without SDP*/
-               if (h->sdp_offering) {
-                       set_sdp_from_desc(msg,h->base.local_media);
-               }else{
-                       if (h->sdp_answer==NULL) sdp_process(h);
-                       if (h->sdp_answer){
-                               set_sdp(msg,h->sdp_answer);
-                               sdp_message_free(h->sdp_answer);
-                               h->sdp_answer=NULL;
-                       }
-               }
-       }else{
-               ms_error("You are accepting a call but not defined any media capabilities !");
-       }
-       eXosip_call_send_answer(h->tid,200,msg);
-       return 0;
-}
-
-int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){
-       if (reason==SalReasonBusy){
-               eXosip_lock();
-               eXosip_call_send_answer(h->tid,486,NULL);
-               eXosip_unlock();
-       }
-       else if (reason==SalReasonTemporarilyUnavailable){
-               eXosip_lock();
-               eXosip_call_send_answer(h->tid,480,NULL);
-               eXosip_unlock();
-       }else if (reason==SalReasonDoNotDisturb){
-               eXosip_lock();
-               eXosip_call_send_answer(h->tid,600,NULL);
-               eXosip_unlock();
-       }else if (reason==SalReasonMedia){
-               eXosip_lock();
-               eXosip_call_send_answer(h->tid,415,NULL);
-               eXosip_unlock();
-       }else if (redirect!=NULL && reason==SalReasonRedirect){
-               osip_message_t *msg;
-               int code;
-               if (strstr(redirect,"sip:")!=0) code=302;
-               else code=380;
-               eXosip_lock();
-               eXosip_call_build_answer(h->tid,code,&msg);
-               osip_message_set_contact(msg,redirect);
-               eXosip_call_send_answer(h->tid,code,msg);
-               eXosip_unlock();
-       }else sal_call_terminate(h);
-       return 0;
-}
-
-SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){
-       return h->base.remote_media;
-}
-
-SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
-       if (h->base.local_media && h->base.remote_media && !h->result){
-               sdp_process(h);
-       }
-       return h->result;
-}
-
-int sal_call_set_referer(SalOp *h, SalOp *refered_call){
-       if (refered_call->replaces)
-               h->replaces=ms_strdup(refered_call->replaces);
-       if (refered_call->referred_by)
-               h->referred_by=ms_strdup(refered_call->referred_by);
-       return 0;
-}
-
-static int send_notify_for_refer(int did, const char *sipfrag){
-       osip_message_t *msg;
-       eXosip_lock();
-       eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);
-       if (msg==NULL){
-               eXosip_unlock();
-               ms_warning("Could not build NOTIFY for refer.");
-               return -1;
-       }
-       osip_message_set_content_type(msg,"message/sipfrag");
-       osip_message_set_header(msg,"Event","refer");
-       osip_message_set_body(msg,sipfrag,strlen(sipfrag));
-       eXosip_call_send_request(did,msg);
-       eXosip_unlock();
-       return 0;
-}
-
-/* currently only support to notify trying and 200Ok*/
-int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){
-       if (newcall==NULL){
-               /* in progress*/
-               send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");
-       }
-       else if (newcall->cid!=-1){
-               if (newcall->did==-1){
-                       /* not yet established*/
-                       if (!newcall->terminated){
-                               /* in progress*/
-                               send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");
-                       }
-               }else{
-                       if (!newcall->terminated){
-                               if (send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n")==-1){
-                                       /* we need previous notify transaction to complete, so buffer the request for later*/
-                                       h->sipfrag_pending="SIP/2.0 200 Ok\r\n";
-                               }
-                       }
-               }
-       }
-       return 0;
-}
-
-int sal_ping(SalOp *op, const char *from, const char *to){
-       osip_message_t *options=NULL;
-       
-       sal_op_set_from(op,from);
-       sal_op_set_to(op,to);
-       sal_exosip_fix_route(op);
-
-       eXosip_options_build_request (&options, sal_op_get_to(op),
-                       sal_op_get_from(op),sal_op_get_route(op));
-       if (options){
-               if (op->base.root->session_expires!=0){
-                       osip_message_set_header(options, "Session-expires", "200");
-                       osip_message_set_supported(options, "timer");
-               }
-               sal_add_other(sal_op_get_sal(op),op,options);
-               return eXosip_options_send_request(options);
-       }
-       return -1;
-}
-
-int sal_call_refer(SalOp *h, const char *refer_to){
-       osip_message_t *msg=NULL;
-       int err=0;
-       eXosip_lock();
-       eXosip_call_build_refer(h->did,refer_to, &msg);
-       if (msg) err=eXosip_call_send_request(h->did, msg);
-       else err=-1;
-       eXosip_unlock();
-       return err;
-}
-
-int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){
-       osip_message_t *msg=NULL;
-       char referto[256]={0};
-       int err=0;
-       eXosip_lock();
-       if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){
-               ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did);
-               eXosip_unlock();
-               return -1;
-       }
-       eXosip_call_build_refer(h->did,referto, &msg);
-       osip_message_set_header(msg,"Referred-By",h->base.from);
-       if (msg) err=eXosip_call_send_request(h->did, msg);
-       else err=-1;
-       eXosip_unlock();
-       return err;
-}
-
-SalOp *sal_call_get_replaces(SalOp *h){
-       if (h!=NULL && h->replaces!=NULL){
-               int cid;
-               eXosip_lock();
-               cid=eXosip_call_find_by_replaces(h->replaces);
-               eXosip_unlock();
-               if (cid>0){
-                       SalOp *ret=sal_find_call(h->base.root,cid);
-                       return ret;
-               }
-       }
-       return NULL;
-}
-
-int sal_call_send_dtmf(SalOp *h, char dtmf){
-       osip_message_t *msg=NULL;
-       char dtmf_body[128];
-       char clen[10];
-
-       eXosip_lock();
-       eXosip_call_build_info(h->did,&msg);
-       if (msg){
-               snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf);
-               osip_message_set_body(msg,dtmf_body,strlen(dtmf_body));
-               osip_message_set_content_type(msg,"application/dtmf-relay");
-               snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body));
-               osip_message_set_content_length(msg,clen);              
-               eXosip_call_send_request(h->did,msg);
-       }
-       eXosip_unlock();
-       return 0;
-}
-
-static void push_auth_to_exosip(const SalAuthInfo *info){
-       const char *userid;
-       if (info->userid==NULL || info->userid[0]=='\0') userid=info->username;
-       else userid=info->userid;
-       ms_message("Authentication info for username [%s], id[%s], realm [%s] added to eXosip", info->username,userid, info->realm);
-       eXosip_add_authentication_info (info->username,userid,
-                                  info->password, NULL,info->realm);
-}
-/*
- * Just for symmetry ;-)
- */
-static void pop_auth_from_exosip() {
-       eXosip_clear_authentication_info();
-}
-
-int sal_call_terminate(SalOp *h){
-       int err;
-       if (h == NULL) return -1;
-       if (h->auth_info) push_auth_to_exosip(h->auth_info);
-       eXosip_lock();
-       err=eXosip_call_terminate(h->cid,h->did);
-       eXosip_unlock();
-       if (!h->base.root->reuse_authorization) pop_auth_from_exosip();
-       if (err!=0){
-               ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did);
-       }
-       h->terminated=TRUE;
-       return 0;
-}
-
-void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){
-       bool_t terminating=FALSE;
-       if (h->pending_auth && strcmp(h->pending_auth->request->sip_method,"BYE")==0) {
-               terminating=TRUE;
-       }
-       if (h->terminated && !terminating) return;
-
-       if (h->pending_auth){
-               push_auth_to_exosip(info);
-               
-        /*FIXME exosip does not take into account this update register message*/
-       /*
-        if (fix_message_contact(h, h->pending_auth->request,h->pending_auth->response)) {
-            
-        };
-       */
-               update_contact_from_response(h,h->pending_auth->response);
-               eXosip_lock();
-               eXosip_default_action(h->pending_auth);
-               eXosip_unlock();
-               ms_message("eXosip_default_action() done");
-               if (!h->base.root->reuse_authorization) pop_auth_from_exosip();
-               
-               if (h->auth_info) sal_auth_info_delete(h->auth_info); /*if already exist*/
-               h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/
-       }
-}
-void sal_op_cancel_authentication(SalOp *h) {
-       if (h->rid >0) {
-               sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure");
-       } else if (h->cid >0) {
-               sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0);
-       } else {
-               ms_warning("Auth failure not handled");
-       }
-
-}
-static void set_network_origin(SalOp *op, osip_message_t *req){
-       const char *received=NULL;
-       int rport=5060;
-       char origin[64]={0};
-    SalTransport transport;
-       if (extract_received_rport(req,&received,&rport,&transport)!=0){
-               osip_via_t *via=NULL;
-               char *tmp;
-               osip_message_get_via(req,0,&via);
-               received=osip_via_get_host(via);
-               tmp=osip_via_get_port(via);
-               if (tmp) rport=atoi(tmp);
-       }
-    if (transport != SalTransportUDP) {
-        snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport);
-    } else {
-       snprintf(origin,sizeof(origin)-1,"sip:%s:%i;transport=%s",received,rport,sal_transport_to_string(transport)); 
-    }
-       __sal_op_set_network_origin(op,origin);
-}
-
-static void set_remote_ua(SalOp* op, osip_message_t *req){
-       if (op->base.remote_ua==NULL){
-               osip_header_t *h=NULL;
-               osip_message_get_user_agent(req,0,&h);
-               if (h){
-                       op->base.remote_ua=ms_strdup(h->hvalue);
-               }
-       }
-}
-
-static void set_remote_contact(SalOp* op, osip_message_t *req){
-       if (op->base.remote_contact==NULL){
-               osip_contact_t *h=NULL;
-               osip_message_get_contact(req,0,&h);
-               if (h){
-                       char *tmp=NULL;
-                       osip_contact_to_str(h,&tmp);
-                       __sal_op_set_remote_contact(op,tmp);
-                       osip_free(tmp);
-               }
-       }
-}
-
-static void set_replaces(SalOp *op, osip_message_t *req){
-       osip_header_t *h=NULL;
-
-       if (op->replaces){
-               ms_free(op->replaces);
-               op->replaces=NULL;
-       }
-       osip_message_header_get_byname(req,"replaces",0,&h);
-       if (h){
-               if (h->hvalue && h->hvalue[0]!='\0'){
-                       op->replaces=ms_strdup(h->hvalue);
-               }
-       }
-}
-
-static SalOp *find_op(Sal *sal, eXosip_event_t *ev){
-       if (ev->cid>0){
-               return sal_find_call(sal,ev->cid);
-       }
-       if (ev->rid>0){
-               return sal_find_register(sal,ev->rid);
-       }
-       if (ev->sid>0){
-               return sal_find_out_subscribe(sal,ev->sid);
-       }
-       if (ev->nid>0){
-               return sal_find_in_subscribe(sal,ev->nid);
-       }
-       if (ev->response) return sal_find_other(sal,ev->response);
-       else if (ev->request) return sal_find_other(sal,ev->request);
-       return NULL;
-}
-
-static void inc_new_call(Sal *sal, eXosip_event_t *ev){
-       SalOp *op=sal_op_new(sal);
-       osip_from_t *from,*to;
-       osip_call_info_t *call_info;
-       char *tmp=NULL;
-       sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);
-       
-       osip_call_id_t *callid=osip_message_get_call_id(ev->request);
-       
-       osip_call_id_to_str(callid,&tmp);
-       op->base.call_id=ms_strdup(tmp);
-       osip_free(tmp);
-       
-       set_network_origin(op,ev->request);
-       set_remote_contact(op,ev->request);
-       set_remote_ua(op,ev->request);
-       set_replaces(op,ev->request);
-       
-       if (sdp){
-               op->sdp_offering=FALSE;
-               op->base.remote_media=sal_media_description_new();
-               sdp_to_media_description(sdp,op->base.remote_media);
-               sdp_message_free(sdp);
-       }else op->sdp_offering=TRUE;
-
-       from=osip_message_get_from(ev->request);
-       to=osip_message_get_to(ev->request);
-       osip_from_to_str(from,&tmp);
-       sal_op_set_from(op,tmp);
-       osip_free(tmp);
-       osip_from_to_str(to,&tmp);
-       sal_op_set_to(op,tmp);
-       osip_free(tmp);
-
-       osip_message_get_call_info(ev->request,0,&call_info);
-       if(call_info)
-       {
-               osip_call_info_to_str(call_info,&tmp);
-               if( strstr(tmp,"answer-after=") != NULL)
-               {
-                       op->auto_answer_asked=TRUE;
-                       ms_message("The caller asked to automatically answer the call(Emergency?)\n");
-               }
-               osip_free(tmp);
-       }
-
-       op->tid=ev->tid;
-       op->cid=ev->cid;
-       op->did=ev->did;
-       sal_add_call(op->base.root,op);
-       sal->callbacks.call_received(op);
-}
-
-static void handle_reinvite(Sal *sal,  eXosip_event_t *ev){
-       SalOp *op=find_op(sal,ev);
-       sdp_message_t *sdp;
-
-       if (op==NULL) {
-               ms_warning("Reinvite for non-existing operation !");
-               return;
-       }
-       op->reinvite=TRUE;
-       op->tid=ev->tid;
-       sdp=eXosip_get_sdp_info(ev->request);
-       if (op->base.remote_media){
-               sal_media_description_unref(op->base.remote_media);
-               op->base.remote_media=NULL;
-       }
-       if (op->result){
-               sal_media_description_unref(op->result);
-               op->result=NULL;
-       }
-       if (sdp){
-               op->sdp_offering=FALSE;
-               op->base.remote_media=sal_media_description_new();
-               sdp_to_media_description(sdp,op->base.remote_media);
-               sdp_message_free(sdp);
-               
-       }else {
-               op->sdp_offering=TRUE;
-       }
-       sal->callbacks.call_updating(op);
-}
-
-static void handle_ack(Sal *sal,  eXosip_event_t *ev){
-       SalOp *op=find_op(sal,ev);
-       sdp_message_t *sdp;
-
-       if (op==NULL) {
-               ms_warning("ack for non-existing call !");
-               return;
-       }
-       if (op->terminated) {
-               ms_warning("ack for terminated call, ignoring");
-               return;
-       }
-       
-       if (op->sdp_offering){
-               sdp=eXosip_get_sdp_info(ev->ack);
-               if (sdp){
-                       if (op->base.remote_media)
-                               sal_media_description_unref(op->base.remote_media);
-                       op->base.remote_media=sal_media_description_new();
-                       sdp_to_media_description(sdp,op->base.remote_media);
-                       sdp_process(op);
-                       sdp_message_free(sdp);
-               }
-       }
-       if (op->reinvite){
-               op->reinvite=FALSE;
-       }
-       sal->callbacks.call_ack(op);
-}
-
-static void update_contact_from_response(SalOp *op, osip_message_t *response){
-       const char *received;
-       int rport;
-       SalTransport transport;
-       if (extract_received_rport(response,&received,&rport,&transport)==0){
-               const char *contact=sal_op_get_contact(op);
-               if (!contact){
-                       /*no contact given yet, use from instead*/
-                       contact=sal_op_get_from(op);
-               }
-               if (contact){
-                       SalAddress *addr=sal_address_new(contact);
-                       char *tmp;
-                       sal_address_set_domain(addr,received);
-                       sal_address_set_port_int(addr,rport);
-                       if (transport!=SalTransportUDP)
-                               sal_address_set_transport(addr,transport);
-                       tmp=sal_address_as_string(addr);
-                       ms_message("Contact address updated to %s",tmp);
-                       sal_op_set_contact(op,tmp);
-                       sal_address_destroy(addr);
-                       ms_free(tmp);
-               }
-       }
-}
-
-static int call_proceeding(Sal *sal, eXosip_event_t *ev){
-       SalOp *op=find_op(sal,ev);
-
-       if (op==NULL || op->terminated==TRUE) {
-               ms_warning("This call has been canceled.");
-               eXosip_lock();
-               eXosip_call_terminate(ev->cid,ev->did);
-               eXosip_unlock();
-               return -1;
-       }
-       if (ev->did>0)
-               op->did=ev->did;
-       op->tid=ev->tid;
-       
-       /* update contact if received and rport are set by the server
-        note: will only be used by remote for next INVITE, if any...*/
-       update_contact_from_response(op,ev->response);
-       return 0;
-}
-
-static void call_ringing(Sal *sal, eXosip_event_t *ev){
-       sdp_message_t *sdp;
-       SalOp *op=find_op(sal,ev);
-       if (call_proceeding(sal, ev)==-1) return;
-
-       set_remote_ua(op,ev->response);
-       sdp=eXosip_get_sdp_info(ev->response);
-       if (sdp){
-               op->base.remote_media=sal_media_description_new();
-               sdp_to_media_description(sdp,op->base.remote_media);
-               sdp_message_free(sdp);
-               if (op->base.local_media) sdp_process(op);
-       }
-       sal->callbacks.call_ringing(op);
-}
-
-static void call_accepted(Sal *sal, eXosip_event_t *ev){
-       sdp_message_t *sdp;
-       osip_message_t *msg=NULL;
-       SalOp *op=find_op(sal,ev);
-       const char *contact;
-       
-       if (op==NULL || op->terminated==TRUE) {
-               ms_warning("This call has been already terminated.");
-               eXosip_lock();
-               eXosip_call_terminate(ev->cid,ev->did);
-               eXosip_unlock();
-               return ;
-       }
-
-       op->did=ev->did;
-       set_remote_ua(op,ev->response);
-       set_remote_contact(op,ev->response);
-
-       sdp=eXosip_get_sdp_info(ev->response);
-       if (sdp){
-               op->base.remote_media=sal_media_description_new();
-               sdp_to_media_description(sdp,op->base.remote_media);
-               sdp_message_free(sdp);
-               if (op->base.local_media) sdp_process(op);
-       }
-       eXosip_call_build_ack(ev->did,&msg);
-       if (msg==NULL) {
-               ms_warning("This call has been already terminated.");
-               eXosip_lock();
-               eXosip_call_terminate(ev->cid,ev->did);
-               eXosip_unlock();
-               return ;
-       }
-       contact=sal_op_get_contact(op);
-       if (contact) {
-               _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
-               osip_message_set_contact(msg,contact);
-       }
-       if (op->sdp_answer){
-               set_sdp(msg,op->sdp_answer);
-               sdp_message_free(op->sdp_answer);
-               op->sdp_answer=NULL;
-       }
-       eXosip_call_send_ack(ev->did,msg);
-       sal->callbacks.call_accepted(op);
-}
-
-static void call_terminated(Sal *sal, eXosip_event_t *ev){
-       char *from=NULL;
-       SalOp *op=find_op(sal,ev);
-       if (op==NULL){
-               ms_warning("Call terminated for already closed call ?");
-               return;
-       }
-       if (ev->request){
-               osip_from_to_str(ev->request->from,&from);
-       }
-       sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op));
-       if (from) osip_free(from);
-       op->terminated=TRUE;
-}
-
-static void call_released(Sal *sal, eXosip_event_t *ev){
-       SalOp *op=find_op(sal,ev);
-       if (op==NULL){
-               ms_warning("No op associated to this call_released()");
-               return;
-       }
-       if (!op->terminated){
-               /* no response received so far */
-               call_failure(sal,ev);
-       }
-       sal->callbacks.call_released(op);
-}
-
-static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){
-       const char *prx_realm=NULL,*www_realm=NULL;
-       osip_proxy_authenticate_t *prx_auth;
-       osip_www_authenticate_t *www_auth;
-       
-       *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){
-               *realm=prx_realm;
-       }else if (www_realm){
-               *realm=www_realm;
-       }else{
-               return -1;
-       }
-       return 0;
-}
-
-static int get_auth_data_from_request(osip_message_t *msg, const char **realm, const char **username){
-       osip_authorization_t *auth=NULL;
-       osip_proxy_authorization_t *prx_auth=NULL;
-       
-       *username=osip_uri_get_username(msg->from->url);
-       osip_message_get_authorization(msg, 0, &auth);
-       if (auth){
-               *realm=osip_authorization_get_realm(auth);
-               return 0;
-       }
-       osip_message_get_proxy_authorization(msg,0,&prx_auth);
-       if (prx_auth){
-               *realm=osip_proxy_authorization_get_realm(prx_auth);
-               return 0;
-       }
-       return -1;
-}
-
-static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){
-       if (ev->response && get_auth_data_from_response(ev->response,realm,username)==0) return 0;
-       if (ev->request && get_auth_data_from_request(ev->request,realm,username)==0) return 0;
-       return -1;
-}
-
-int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){
-       if (op->pending_auth){
-               return get_auth_data(op->pending_auth,realm,username);
-       }
-       return -1;
-}
-
-static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){
-       SalOp *op;
-       const char *username,*realm;
-       op=find_op(sal,ev);
-       if (op==NULL){
-               ms_warning("No operation associated with this authentication !");
-               return TRUE;
-       }
-       if (get_auth_data(ev,&realm,&username)==0){
-               if (op->pending_auth!=NULL){
-                       eXosip_event_free(op->pending_auth);
-                       op->pending_auth=ev;
-               }else{
-                       op->pending_auth=ev;
-                       sal_add_pending_auth(sal,op);
-               }
-               
-               sal->callbacks.auth_requested(op,realm,username);
-               return FALSE;
-       }
-       return TRUE;
-}
-
-static void authentication_ok(Sal *sal, eXosip_event_t *ev){
-       SalOp *op;
-       const char *username,*realm;
-       op=find_op(sal,ev);
-       if (op==NULL){
-               ms_warning("No operation associated with this authentication_ok!");
-               return ;
-       }
-       if (op->pending_auth){
-               eXosip_event_free(op->pending_auth);
-               sal_remove_pending_auth(sal,op);
-               op->pending_auth=NULL;
-       }
-       if (get_auth_data(ev,&realm,&username)==0){
-               sal->callbacks.auth_success(op,realm,username);
-       }
-}
-
-static bool_t call_failure(Sal *sal, eXosip_event_t *ev){
-       SalOp *op;
-       int code=0;
-       char* computedReason=NULL;
-       const char *reason=NULL;
-       SalError error=SalErrorUnknown;
-       SalReason sr=SalReasonUnknown;
-       
-
-       op=(SalOp*)find_op(sal,ev);
-
-       if (op==NULL) {
-               ms_warning("Call failure reported for a closed call, ignored.");
-               return TRUE;
-       }
-
-       if (ev->response){
-               code=osip_message_get_status_code(ev->response);
-               reason=osip_message_get_reason_phrase(ev->response);
-               osip_header_t *h=NULL;
-               if (!osip_message_header_get_byname(    ev->response
-                                                                                       ,"Reason"
-                                                                                       ,0
-                                                                                       ,&h)) {
-                       computedReason = ms_strdup_printf("%s %s",reason,osip_header_get_value(h));
-                       reason = computedReason;
-
-               }
-       }
-       switch(code)
-       {
-               case 401:
-               case 407:
-                       return process_authentication(sal,ev);
-                       break;
-               case 400:
-                       error=SalErrorUnknown;
-               break;
-               case 404:
-                       error=SalErrorFailure;
-                       sr=SalReasonNotFound;
-               break;
-               case 415:
-                       error=SalErrorFailure;
-                       sr=SalReasonMedia;
-               break;
-               case 422:
-                       eXosip_default_action(ev);
-                       return TRUE;
-               break;
-               case 480:
-                       error=SalErrorFailure;
-                       sr=SalReasonTemporarilyUnavailable;
-               case 486:
-                       error=SalErrorFailure;
-                       sr=SalReasonBusy;
-               break;
-               case 487:
-               break;
-               case 600:
-                       error=SalErrorFailure;
-                       sr=SalReasonDoNotDisturb;
-               break;
-               case 603:
-                       error=SalErrorFailure;
-                       sr=SalReasonDeclined;
-               break;
-               default:
-                       if (code>0){
-                               error=SalErrorFailure;
-                               sr=SalReasonUnknown;
-                       }else error=SalErrorNoResponse;
-       }
-       op->terminated=TRUE;
-       sal->callbacks.call_failure(op,error,sr,reason,code);
-       if (computedReason != NULL){
-               ms_free(computedReason);
-       }
-       return TRUE;
-}
-
-/* Request remote side to send us VFU */
-void sal_call_send_vfu_request(SalOp *h){
-       osip_message_t *msg=NULL;
-       char info_body[] =
-                       "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
-                        "<media_control>"
-                        "  <vc_primitive>"
-                        "    <to_encoder>"
-                        "      <picture_fast_update></picture_fast_update>"
-                        "    </to_encoder>"
-                        "  </vc_primitive>"
-                        "</media_control>";
-
-       char clen[10];
-
-       eXosip_lock();
-       eXosip_call_build_info(h->did,&msg);
-       if (msg){
-               osip_message_set_body(msg,info_body,strlen(info_body));
-               osip_message_set_content_type(msg,"application/media_control+xml");
-               snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(info_body));
-               osip_message_set_content_length(msg,clen);
-               eXosip_call_send_request(h->did,msg);
-               ms_message("Sending VFU request !");
-       }
-       eXosip_unlock();
-}
-
-static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){
-       SalOp *op=find_op(sal,ev);
-       osip_body_t *body=NULL;
-
-       if (op==NULL){
-               ms_warning("media control xml received without operation context!");
-               return ;
-       }
-       
-       osip_message_get_body(ev->request,0,&body);
-       if (body && body->body!=NULL &&
-               strstr(body->body,"picture_fast_update")){
-               osip_message_t *ans=NULL;
-               ms_message("Receiving VFU request !");
-               if (sal->callbacks.vfu_request){
-                       sal->callbacks.vfu_request(op);
-                       eXosip_call_build_answer(ev->tid,200,&ans);
-                       if (ans)
-                               eXosip_call_send_answer(ev->tid,200,ans);
-                       return;
-               }
-       }
-       /*in all other cases we must say it is not implemented.*/
-       {
-               osip_message_t *ans=NULL;
-               eXosip_lock();
-               eXosip_call_build_answer(ev->tid,501,&ans);
-               if (ans)
-                       eXosip_call_send_answer(ev->tid,501,ans);
-               eXosip_unlock();
-       }
-}
-
-static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){
-       SalOp *op=find_op(sal,ev);
-       osip_body_t *body=NULL;
-
-       if (op==NULL){
-               ms_warning("media dtmf relay received without operation context!");
-               return ;
-       }
-       
-       osip_message_get_body(ev->request,0,&body);
-       if (body && body->body!=NULL){
-               osip_message_t *ans=NULL;
-               const char *name=strstr(body->body,"Signal");
-               if (name==NULL) name=strstr(body->body,"signal");
-               if (name==NULL) {
-                       ms_warning("Could not extract the dtmf name from the SIP INFO.");
-               }else{
-                       char tmp[2];
-                       name+=strlen("signal");
-                       if (sscanf(name," = %1s",tmp)==1){
-                               ms_message("Receiving dtmf %s via SIP INFO.",tmp);
-                               if (sal->callbacks.dtmf_received != NULL)
-                                       sal->callbacks.dtmf_received(op, tmp[0]);
-                       }
-               }
-               eXosip_lock();
-               eXosip_call_build_answer(ev->tid,200,&ans);
-               if (ans)
-                       eXosip_call_send_answer(ev->tid,200,ans);
-               eXosip_unlock();
-       }
-}
-
-static void fill_options_answer(osip_message_t *options){
-       osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO");
-       osip_message_set_accept(options,"application/sdp");
-}
-
-static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){
-       osip_header_t *h=NULL;
-       osip_message_t *ans=NULL;
-       ms_message("Receiving REFER request !");
-       osip_message_header_get_byname(ev->request,"Refer-To",0,&h);
-
-       if (h){
-               osip_from_t *from=NULL;
-               char *tmp;
-               osip_from_init(&from);
-       
-               if (osip_from_parse(from,h->hvalue)==0){
-                       if (op ){
-                               osip_uri_header_t *uh=NULL;
-                               osip_header_t *referred_by=NULL;
-                               osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh);
-                               if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){
-                                       ms_message("Found replaces in Refer-To");
-                                       if (op->replaces){
-                                               ms_free(op->replaces);
-                                       }
-                                       op->replaces=ms_strdup(uh->gvalue);
-                               }
-                               osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by);
-                               if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){
-                                       if (op->referred_by)
-                                               ms_free(op->referred_by);
-                                       op->referred_by=ms_strdup(referred_by->hvalue);
-                               }
-                       }
-                       osip_uri_header_freelist(&from->url->url_headers);
-                       osip_from_to_str(from,&tmp);
-                       sal->callbacks.refer_received(sal,op,tmp);
-                       osip_free(tmp);
-                       osip_from_free(from);
-               }
-               eXosip_lock();
-               eXosip_call_build_answer(ev->tid,202,&ans);
-               if (ans)
-                       eXosip_call_send_answer(ev->tid,202,ans);
-               eXosip_unlock();
-       }
-       else
-       {
-               ms_warning("cannot do anything with the refer without destination\n");
-       }
-}
-
-static void process_notify(Sal *sal, eXosip_event_t *ev){
-       osip_header_t *h=NULL;
-       char *from=NULL;
-       SalOp *op=find_op(sal,ev);
-       osip_message_t *ans=NULL;
-
-       ms_message("Receiving NOTIFY request !");
-       osip_from_to_str(ev->request->from,&from);
-       osip_message_header_get_byname(ev->request,"Event",0,&h);
-       if(h){
-               osip_body_t *body=NULL;
-               //osip_content_type_t *ct=NULL;
-               osip_message_get_body(ev->request,0,&body);
-               //ct=osip_message_get_content_type(ev->request);
-               if (h->hvalue && strcasecmp(h->hvalue,"refer")==0){
-                       /*special handling of refer events*/
-                       if (body && body->body){
-                               osip_message_t *msg;
-                               osip_message_init(&msg);
-                               if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){
-                                       int code=osip_message_get_status_code(msg);
-                                       if (code==100){
-                                               sal->callbacks.notify_refer(op,SalReferTrying);
-                                       }else if (code==200){
-                                               sal->callbacks.notify_refer(op,SalReferSuccess);
-                                       }else if (code>=400){
-                                               sal->callbacks.notify_refer(op,SalReferFailed);
-                                       }
-                               }
-                               osip_message_free(msg);
-                       }
-               }else{
-                       /*generic handling*/
-                       sal->callbacks.notify(op,from,h->hvalue);
-               }
-       }
-       /*answer that we received the notify*/
-       eXosip_lock();
-       eXosip_call_build_answer(ev->tid,200,&ans);
-       if (ans)
-               eXosip_call_send_answer(ev->tid,200,ans);
-       eXosip_unlock();
-       osip_free(from);
-}
-
-static void call_message_new(Sal *sal, eXosip_event_t *ev){
-       osip_message_t *ans=NULL;
-       if (ev->request){
-               if (MSG_IS_INFO(ev->request)){
-                       osip_content_type_t *ct;
-                       ct=osip_message_get_content_type(ev->request);
-                       if (ct && ct->subtype){
-                               if (strcmp(ct->subtype,"media_control+xml")==0)
-                                       process_media_control_xml(sal,ev);
-                               else if (strcmp(ct->subtype,"dtmf-relay")==0)
-                                       process_dtmf_relay(sal,ev);
-                               else {
-                                       ms_message("Unhandled SIP INFO.");
-                                       /*send an "Not implemented" answer*/
-                                       eXosip_lock();
-                                       eXosip_call_build_answer(ev->tid,501,&ans);
-                                       if (ans)
-                                               eXosip_call_send_answer(ev->tid,501,ans);
-                                       eXosip_unlock();
-                               }
-                       }else{
-                               /*empty SIP INFO, probably to test we are alive. Send an empty answer*/
-                               eXosip_lock();
-                               eXosip_call_build_answer(ev->tid,200,&ans);
-                               if (ans)
-                                       eXosip_call_send_answer(ev->tid,200,ans);
-                               eXosip_unlock();
-                       }
-               }else if(MSG_IS_MESSAGE(ev->request)){
-                       /* SIP messages could be received into call */
-                       text_received(sal, ev);
-                       eXosip_lock();
-                       eXosip_call_build_answer(ev->tid,200,&ans);
-                       if (ans)
-                               eXosip_call_send_answer(ev->tid,200,ans);
-                       eXosip_unlock();
-               }else if(MSG_IS_REFER(ev->request)){
-                       SalOp *op=find_op(sal,ev);
-                       
-                       ms_message("Receiving REFER request !");
-                       process_refer(sal,op,ev);
-               }else if(MSG_IS_NOTIFY(ev->request)){
-                       process_notify(sal,ev);
-               }else if (MSG_IS_OPTIONS(ev->request)){
-                       eXosip_lock();
-                       eXosip_call_build_answer(ev->tid,200,&ans);
-                       if (ans){
-                               fill_options_answer(ans);
-                               eXosip_call_send_answer(ev->tid,200,ans);
-                       }
-                       eXosip_unlock();
-               }
-       }else ms_warning("call_message_new: No request ?");
-}
-
-static void inc_update(Sal *sal, eXosip_event_t *ev){
-       osip_message_t *msg=NULL;
-       ms_message("Processing incoming UPDATE");
-       eXosip_lock();
-       eXosip_message_build_answer(ev->tid,200,&msg);
-       if (msg!=NULL)
-               eXosip_message_send_answer(ev->tid,200,msg);
-       eXosip_unlock();
-}
-
-static bool_t comes_from_local_if(osip_message_t *msg){
-       osip_via_t *via=NULL;
-       osip_message_get_via(msg,0,&via);
-       if (via){
-               const char *host;
-               host=osip_via_get_host(via);
-               if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){
-                       osip_generic_param_t *param=NULL;
-                       osip_via_param_get_byname(via,"received",&param);
-                       if (param==NULL) return TRUE;
-                       if (param->gvalue &&
-                               (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){
-                               return TRUE;
-                       }
-               }
-       }
-       return FALSE;
-}
-
+/*\r
+linphone\r
+Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)\r
+\r
+This program is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License\r
+as published by the Free Software Foundation; either version 2\r
+of the License, or (at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+*/\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "sal_eXosip2.h"\r
+#include "offeranswer.h"\r
+\r
+#ifdef ANDROID\r
+// Necessary to make it linked\r
+static void for_linker() { eXosip_transport_hook_register(NULL); }\r
+#endif\r
+static bool_t call_failure(Sal *sal, eXosip_event_t *ev);\r
+\r
+static void text_received(Sal *sal, eXosip_event_t *ev);\r
+\r
+static void masquerade_via(osip_message_t *msg, const char *ip, const char *port);\r
+static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact);\r
+static void update_contact_from_response(SalOp *op, osip_message_t *response);\r
+\r
+\r
+void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){\r
+       void *data;\r
+       while(!osip_list_eol(l,0)) {\r
+               data=osip_list_get(l,0);\r
+               osip_list_remove(l,0);\r
+               if (data) freefunc(data);\r
+       }\r
+}\r
+\r
+void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iplen){\r
+       if (eXosip_guess_localip(address_family,ip,iplen)<0){\r
+               /*default to something */\r
+               strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen);\r
+               ms_error("Could not find default routable ip address !");\r
+       }\r
+}\r
+\r
+static SalOp * sal_find_call(Sal *sal, int cid){\r
+       const MSList *elem;\r
+       SalOp *op;\r
+       for(elem=sal->calls;elem!=NULL;elem=elem->next){\r
+               op=(SalOp*)elem->data;\r
+               if (op->cid==cid) return op;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+static void sal_add_call(Sal *sal, SalOp *op){\r
+       sal->calls=ms_list_append(sal->calls,op);\r
+}\r
+\r
+static void sal_remove_call(Sal *sal, SalOp *op){\r
+       sal->calls=ms_list_remove(sal->calls, op);\r
+}\r
+\r
+static SalOp * sal_find_register(Sal *sal, int rid){\r
+       const MSList *elem;\r
+       SalOp *op;\r
+       for(elem=sal->registers;elem!=NULL;elem=elem->next){\r
+               op=(SalOp*)elem->data;\r
+               if (op->rid==rid) return op;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+static void sal_add_register(Sal *sal, SalOp *op){\r
+       sal->registers=ms_list_append(sal->registers,op);\r
+}\r
+\r
+static void sal_remove_register(Sal *sal, int rid){\r
+       MSList *elem;\r
+       SalOp *op;\r
+       for(elem=sal->registers;elem!=NULL;elem=elem->next){\r
+               op=(SalOp*)elem->data;\r
+               if (op->rid==rid) {\r
+                       sal->registers=ms_list_remove_link(sal->registers,elem);\r
+                       return;\r
+               }\r
+       }\r
+}\r
+\r
+static SalOp * sal_find_other(Sal *sal, osip_message_t *message){\r
+       const MSList *elem;\r
+       SalOp *op;\r
+       osip_call_id_t *callid=osip_message_get_call_id(message);\r
+       if (callid==NULL) {\r
+               ms_error("There is no call-id in this message !");\r
+               return NULL;\r
+       }\r
+       for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){\r
+               op=(SalOp*)elem->data;\r
+               if (osip_call_id_match(callid,op->call_id)==0) return op;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){\r
+       osip_call_id_t *callid=osip_message_get_call_id(request);\r
+       if (callid==NULL) {\r
+               ms_error("There is no call id in the request !");\r
+               return;\r
+       }\r
+       osip_call_id_clone(callid,&op->call_id);\r
+       sal->other_transactions=ms_list_append(sal->other_transactions,op);\r
+}\r
+\r
+static void sal_remove_other(Sal *sal, SalOp *op){\r
+       sal->other_transactions=ms_list_remove(sal->other_transactions,op);\r
+}\r
+\r
+\r
+static void sal_add_pending_auth(Sal *sal, SalOp *op){\r
+       sal->pending_auths=ms_list_append(sal->pending_auths,op);\r
+}\r
+\r
+\r
+static void sal_remove_pending_auth(Sal *sal, SalOp *op){\r
+       sal->pending_auths=ms_list_remove(sal->pending_auths,op);\r
+}\r
+\r
+void sal_exosip_fix_route(SalOp *op){\r
+       if (sal_op_get_route(op)!=NULL){\r
+               osip_route_t *rt=NULL;\r
+               osip_uri_param_t *lr_param=NULL;\r
+               \r
+               osip_route_init(&rt);\r
+               if (osip_route_parse(rt,sal_op_get_route(op))<0){\r
+                       ms_warning("Bad route  %s!",sal_op_get_route(op));\r
+                       sal_op_set_route(op,NULL);\r
+               }else{\r
+                       /* check if the lr parameter is set , if not add it */\r
+                       osip_uri_uparam_get_byname(rt->url, "lr", &lr_param);\r
+                       if (lr_param==NULL){\r
+                               char *tmproute;\r
+                               osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL);\r
+                               osip_route_to_str(rt,&tmproute);\r
+                               sal_op_set_route(op,tmproute);\r
+                               osip_free(tmproute);\r
+                       }\r
+               }\r
+               osip_route_free(rt);\r
+       }\r
+}\r
+\r
+SalOp * sal_op_new(Sal *sal){\r
+       SalOp *op=ms_new0(SalOp,1);\r
+       __sal_op_init(op,sal);\r
+       op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1;\r
+       op->result=NULL;\r
+       op->supports_session_timers=FALSE;\r
+       op->sdp_offering=TRUE;\r
+       op->pending_auth=NULL;\r
+       op->sdp_answer=NULL;\r
+       op->reinvite=FALSE;\r
+       op->call_id=NULL;\r
+       op->replaces=NULL;\r
+       op->referred_by=NULL;\r
+       op->masquerade_via=FALSE;\r
+       op->auto_answer_asked=FALSE;\r
+       op->auth_info=NULL;\r
+       op->terminated=FALSE;\r
+       return op;\r
+}\r
+\r
+bool_t sal_call_autoanswer_asked(SalOp *op)\r
+{\r
+       return op->auto_answer_asked;\r
+}\r
+\r
+void sal_op_release(SalOp *op){\r
+       if (op->sdp_answer)\r
+               sdp_message_free(op->sdp_answer);\r
+       if (op->pending_auth)\r
+               eXosip_event_free(op->pending_auth);\r
+       if (op->rid!=-1){\r
+               sal_remove_register(op->base.root,op->rid);\r
+               eXosip_register_remove(op->rid);\r
+       }\r
+       if (op->cid!=-1){\r
+               ms_message("Cleaning cid %i",op->cid);\r
+               sal_remove_call(op->base.root,op);\r
+       }\r
+       if (op->sid!=-1){\r
+               sal_remove_out_subscribe(op->base.root,op);\r
+       }\r
+       if (op->nid!=-1){\r
+               sal_remove_in_subscribe(op->base.root,op);\r
+               if (op->call_id)\r
+                       osip_call_id_free(op->call_id);\r
+               op->call_id=NULL;\r
+       }\r
+       if (op->pending_auth){\r
+               sal_remove_pending_auth(op->base.root,op);\r
+       }\r
+       if (op->result)\r
+               sal_media_description_unref(op->result);\r
+       if (op->call_id){\r
+               sal_remove_other(op->base.root,op);\r
+               osip_call_id_free(op->call_id);\r
+       }\r
+       if (op->replaces){\r
+               ms_free(op->replaces);\r
+       }\r
+       if (op->referred_by){\r
+               ms_free(op->referred_by);\r
+       }\r
+       if (op->auth_info) {\r
+               sal_auth_info_delete(op->auth_info);\r
+       }\r
+       __sal_op_free(op);\r
+}\r
+\r
+static void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){\r
+       int ortp_level=ORTP_DEBUG;\r
+       switch(level){\r
+               case OSIP_INFO1:\r
+               case OSIP_INFO2:\r
+               case OSIP_INFO3:\r
+               case OSIP_INFO4:\r
+                       ortp_level=ORTP_MESSAGE;\r
+                       break;\r
+               case OSIP_WARNING:\r
+                       ortp_level=ORTP_WARNING;\r
+                       break;\r
+               case OSIP_ERROR:\r
+               case OSIP_BUG:\r
+                       ortp_level=ORTP_ERROR;\r
+                       break;\r
+               case OSIP_FATAL:\r
+                       ortp_level=ORTP_FATAL;\r
+                       break;\r
+               case END_TRACE_LEVEL:\r
+                       break;\r
+       }\r
+       if (ortp_log_level_enabled(level)){\r
+               int len=strlen(chfr);\r
+               char *chfrdup=ortp_strdup(chfr);\r
+               /*need to remove endline*/\r
+               if (len>1){\r
+                       if (chfrdup[len-1]=='\n')\r
+                               chfrdup[len-1]='\0';\r
+                       if (chfrdup[len-2]=='\r')\r
+                               chfrdup[len-2]='\0';\r
+               }\r
+               ortp_logv(ortp_level,chfrdup,ap);\r
+               ortp_free(chfrdup);\r
+       }\r
+}\r
+\r
+\r
+Sal * sal_init(){\r
+       static bool_t firsttime=TRUE;\r
+       Sal *sal;\r
+       if (firsttime){\r
+               osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func);\r
+               firsttime=FALSE;\r
+       }\r
+       eXosip_init();\r
+       sal=ms_new0(Sal,1);\r
+       sal->keepalive_period=30;\r
+       sal->double_reg=TRUE;\r
+       sal->use_rports=TRUE;\r
+       sal->use_101=TRUE;\r
+       sal->reuse_authorization=FALSE;\r
+       sal->rootCa = 0;\r
+       sal->verify_server_certs=TRUE;\r
+       sal->verify_server_cn=TRUE;\r
+       sal->expire_old_contact=FALSE;\r
+       sal->add_dates=FALSE;\r
+       sal->dscp=-1;\r
+       return sal;\r
+}\r
+\r
+void sal_uninit(Sal* sal){\r
+       eXosip_quit();\r
+       if (sal->rootCa)\r
+               ms_free(sal->rootCa);\r
+       ms_free(sal);\r
+}\r
+\r
+void sal_set_user_pointer(Sal *sal, void *user_data){\r
+       sal->up=user_data;\r
+}\r
+\r
+void *sal_get_user_pointer(const Sal *sal){\r
+       return sal->up;\r
+}\r
+\r
+static void unimplemented_stub(){\r
+       ms_warning("Unimplemented SAL callback");\r
+}\r
+\r
+void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){\r
+       memcpy(&ctx->callbacks,cbs,sizeof(*cbs));\r
+       if (ctx->callbacks.call_received==NULL) \r
+               ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub;\r
+       if (ctx->callbacks.call_ringing==NULL) \r
+               ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub;\r
+       if (ctx->callbacks.call_accepted==NULL) \r
+               ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub;\r
+       if (ctx->callbacks.call_failure==NULL) \r
+               ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;\r
+       if (ctx->callbacks.call_terminated==NULL) \r
+               ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;\r
+       if (ctx->callbacks.call_released==NULL)\r
+               ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub;\r
+       if (ctx->callbacks.call_updating==NULL) \r
+               ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;\r
+       if (ctx->callbacks.auth_requested==NULL) \r
+               ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;\r
+       if (ctx->callbacks.auth_success==NULL) \r
+               ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub;\r
+       if (ctx->callbacks.register_success==NULL) \r
+               ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub;\r
+       if (ctx->callbacks.register_failure==NULL) \r
+               ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub;\r
+       if (ctx->callbacks.dtmf_received==NULL) \r
+               ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub;\r
+       if (ctx->callbacks.notify==NULL)\r
+               ctx->callbacks.notify=(SalOnNotify)unimplemented_stub;\r
+       if (ctx->callbacks.notify_presence==NULL)\r
+               ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub;\r
+       if (ctx->callbacks.subscribe_received==NULL)\r
+               ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub;\r
+       if (ctx->callbacks.text_received==NULL)\r
+               ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;\r
+       if (ctx->callbacks.ping_reply==NULL)\r
+               ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;\r
+}\r
+\r
+int sal_unlisten_ports(Sal *ctx){\r
+       if (ctx->running){\r
+               eXosip_quit();\r
+               eXosip_init();\r
+               ctx->running=FALSE;\r
+       }\r
+       return 0;\r
+}\r
+\r
+int sal_reset_transports(Sal *ctx){\r
+#ifdef HAVE_EXOSIP_RESET_TRANSPORTS\r
+       if (ctx->running){\r
+               ms_message("Exosip transports reset.");\r
+               eXosip_reset_transports();\r
+       }\r
+       return 0;\r
+#else\r
+       ms_warning("sal_reset_transports() not implemented in this version.");\r
+       return -1;\r
+#endif\r
+}\r
+\r
+\r
+static void set_tls_options(Sal *ctx){\r
+       if (ctx->rootCa) {\r
+               eXosip_tls_ctx_t tlsCtx;\r
+               memset(&tlsCtx, 0, sizeof(tlsCtx));\r
+               snprintf(tlsCtx.root_ca_cert, sizeof(tlsCtx.client.cert), "%s", ctx->rootCa);\r
+               eXosip_set_tls_ctx(&tlsCtx);\r
+       }                       \r
+#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE\r
+       eXosip_tls_verify_certificate(ctx->verify_server_certs);\r
+#endif\r
+#ifdef HAVE_EXOSIP_TLS_VERIFY_CN\r
+       eXosip_tls_verify_cn(ctx->verify_server_cn);\r
+#endif\r
+}\r
+\r
+void sal_set_dscp(Sal *ctx, int dscp){\r
+       ctx->dscp=dscp;\r
+#ifdef HAVE_EXOSIP_DSCP\r
+       if (dscp!=-1)\r
+               eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp);\r
+#endif\r
+}\r
+\r
+int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){\r
+       int err;\r
+       bool_t ipv6;\r
+       int proto=IPPROTO_UDP;\r
+       int keepalive = ctx->keepalive_period;\r
+\r
+       ctx->transport = tr;\r
+       switch (tr) {\r
+       case SalTransportUDP:\r
+               proto=IPPROTO_UDP;\r
+               eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &keepalive);\r
+               break;\r
+       case SalTransportTCP:\r
+       case SalTransportTLS:\r
+               proto= IPPROTO_TCP;\r
+               if (!ctx->tcp_tls_keepalive) keepalive=-1;\r
+               eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive);\r
+               set_tls_options(ctx);\r
+               break;\r
+       default:\r
+               ms_warning("unexpected proto, using datagram");\r
+       }\r
+       /*see if it looks like an IPv6 address*/\r
+       int use_rports = ctx->use_rports; // Copy char to int to avoid bad alignment\r
+       eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports);\r
+       int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment\r
+       eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101);\r
+       sal_set_dscp(ctx,ctx->dscp);\r
+       sal_use_dates(ctx,ctx->add_dates);\r
+\r
+       ipv6=strchr(addr,':')!=NULL;\r
+       eXosip_enable_ipv6(ipv6);\r
+\r
+       if (is_secure && tr == SalTransportUDP){\r
+               ms_fatal("SIP over DTLS is not supported yet.");\r
+               return -1;\r
+       }\r
+       err=eXosip_listen_addr(proto, addr, port, ipv6 ?  PF_INET6 : PF_INET, is_secure);\r
+       ctx->running=TRUE;\r
+       return err;\r
+}\r
+\r
+ortp_socket_t sal_get_socket(Sal *ctx){\r
+#ifdef HAVE_EXOSIP_GET_SOCKET\r
+       return eXosip_get_socket(IPPROTO_UDP);\r
+#else\r
+       ms_warning("Sorry, eXosip does not have eXosip_get_socket() method");\r
+       return -1;\r
+#endif\r
+}\r
+\r
+void sal_set_user_agent(Sal *ctx, const char *user_agent){\r
+       eXosip_set_user_agent(user_agent);\r
+}\r
+\r
+void sal_use_session_timers(Sal *ctx, int expires){\r
+       ctx->session_expires=expires;\r
+}\r
+\r
+void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){\r
+       ctx->one_matching_codec=one_matching_codec;\r
+}\r
+\r
+MSList *sal_get_pending_auths(Sal *sal){\r
+       return ms_list_copy(sal->pending_auths);\r
+}\r
+\r
+void sal_use_double_registrations(Sal *ctx, bool_t enabled){\r
+       ctx->double_reg=enabled;\r
+}\r
+\r
+void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){\r
+       ctx->expire_old_contact=enabled;\r
+}\r
+\r
+void sal_use_dates(Sal *ctx, bool_t enabled){\r
+       ctx->add_dates=enabled;\r
+#ifdef EXOSIP_OPT_REGISTER_WITH_DATE\r
+       {\r
+               int tmp=enabled;\r
+               eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp);\r
+       }\r
+#else\r
+       if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option.");\r
+#endif\r
+}\r
+\r
+void sal_use_rport(Sal *ctx, bool_t use_rports){\r
+       ctx->use_rports=use_rports;\r
+}\r
+void sal_use_101(Sal *ctx, bool_t use_101){\r
+       ctx->use_101=use_101;\r
+}\r
+\r
+void sal_set_root_ca(Sal* ctx, const char* rootCa) {\r
+       if (ctx->rootCa)\r
+               ms_free(ctx->rootCa);\r
+       ctx->rootCa = ms_strdup(rootCa);\r
+       set_tls_options(ctx);\r
+}\r
+\r
+const char *sal_get_root_ca(Sal* ctx) {\r
+       return ctx->rootCa;\r
+}\r
+\r
+void sal_verify_server_certificates(Sal *ctx, bool_t verify){\r
+       ctx->verify_server_certs=verify;\r
+#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE\r
+       eXosip_tls_verify_certificate(verify);\r
+#endif\r
+}\r
+\r
+void sal_verify_server_cn(Sal *ctx, bool_t verify){\r
+       ctx->verify_server_cn=verify;\r
+#ifdef HAVE_EXOSIP_TLS_VERIFY_CN\r
+       eXosip_tls_verify_cn(verify);\r
+#endif\r
+}\r
+\r
+static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval,SalTransport* transport){\r
+       osip_via_t *via=NULL;\r
+       osip_generic_param_t *param=NULL;\r
+       const char *rport=NULL;\r
+\r
+       *rportval=5060;\r
+       *received=NULL;\r
+       osip_message_get_via(msg,0,&via);\r
+       if (!via) {\r
+               ms_warning("extract_received_rport(): no via.");\r
+               return -1;\r
+       }\r
+\r
+       *transport = sal_transport_parse(via->protocol);\r
+       \r
+       if (via->port && via->port[0]!='\0')\r
+               *rportval=atoi(via->port);\r
+       \r
+       osip_via_param_get_byname(via,"rport",&param);\r
+       if (param) {\r
+               rport=param->gvalue;\r
+               if (rport && rport[0]!='\0') *rportval=atoi(rport);\r
+               *received=via->host;\r
+       }\r
+       param=NULL;\r
+       osip_via_param_get_byname(via,"received",&param);\r
+       if (param) *received=param->gvalue;\r
+\r
+       if (rport==NULL && *received==NULL){\r
+               ms_warning("extract_received_rport(): no rport and no received parameters.");\r
+               return -1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+static void set_sdp(osip_message_t *sip,sdp_message_t *msg){\r
+       int sdplen;\r
+       char clen[10];\r
+       char *sdp=NULL;\r
+       sdp_message_to_str(msg,&sdp);\r
+       sdplen=strlen(sdp);\r
+       snprintf(clen,sizeof(clen),"%i",sdplen);\r
+       osip_message_set_body(sip,sdp,sdplen);\r
+       osip_message_set_content_type(sip,"application/sdp");\r
+       osip_message_set_content_length(sip,clen);\r
+       osip_free(sdp);\r
+}\r
+\r
+static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){\r
+       sdp_message_t *msg=media_description_to_sdp(desc);\r
+       if (msg==NULL) {\r
+               ms_error("Fail to print sdp message !");\r
+               return;\r
+       }\r
+       set_sdp(sip,msg);\r
+       sdp_message_free(msg);\r
+}\r
+\r
+static void sdp_process(SalOp *h){\r
+       ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming");\r
+       if (h->result){\r
+               sal_media_description_unref(h->result);\r
+       }\r
+       h->result=sal_media_description_new();\r
+       if (h->sdp_offering){   \r
+               offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result);\r
+       }else{\r
+               int i;\r
+               if (h->sdp_answer){\r
+                       sdp_message_free(h->sdp_answer);\r
+               }\r
+               offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec);\r
+               h->sdp_answer=media_description_to_sdp(h->result);\r
+               /*once we have generated the SDP answer, we modify the result description for processing by the upper layer.\r
+                It should contains media parameters constraint from the remote offer, not our response*/\r
+               strcpy(h->result->addr,h->base.remote_media->addr);\r
+               h->result->bandwidth=h->base.remote_media->bandwidth;\r
+               \r
+               for(i=0;i<h->result->n_active_streams;++i){\r
+                       strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr);\r
+                       strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr);\r
+                       h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime;\r
+                       h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth;\r
+                       h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port;\r
+                       h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port;\r
+                       if (h->result->streams[i].proto == SalProtoRtpSavp) {\r
+                               h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0];\r
+                       }\r
+               }\r
+       }\r
+       \r
+}\r
+\r
+int sal_call_is_offerer(const SalOp *h){\r
+       return h->sdp_offering;\r
+}\r
+\r
+int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){\r
+       if (desc)\r
+               sal_media_description_ref(desc);\r
+       if (h->base.local_media)\r
+               sal_media_description_unref(h->base.local_media);\r
+       h->base.local_media=desc;\r
+       if (h->base.remote_media){\r
+               /*case of an incoming call where we modify the local capabilities between the time\r
+                * the call is ringing and it is accepted (for example if you want to accept without video*/\r
+               /*reset the sdp answer so that it is computed again*/\r
+               if (h->sdp_answer){\r
+                       sdp_message_free(h->sdp_answer);\r
+                       h->sdp_answer=NULL;\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+int sal_call(SalOp *h, const char *from, const char *to){\r
+       int err;\r
+       const char *route;\r
+       osip_message_t *invite=NULL;\r
+       osip_call_id_t *callid;\r
+       sal_op_set_from(h,from);\r
+       sal_op_set_to(h,to);\r
+       sal_exosip_fix_route(h);\r
+       \r
+       h->terminated = FALSE;\r
+\r
+       route = sal_op_get_route(h);\r
+       err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call");\r
+       if (err!=0){\r
+               ms_error("Could not create call. Error %d (from=%s to=%s route=%s)",\r
+                               err, from, to, route);\r
+               return -1;\r
+       }\r
+       osip_message_set_allow(invite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");\r
+       if (h->base.contact){\r
+               _osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free);\r
+               osip_message_set_contact(invite,h->base.contact);\r
+       }\r
+       if (h->base.root->session_expires!=0){\r
+               osip_message_set_header(invite, "Session-expires", "200");\r
+               osip_message_set_supported(invite, "timer");\r
+       }\r
+       sal_exosip_add_custom_headers(invite,h->base.custom_headers);\r
+       if (h->base.local_media){\r
+               h->sdp_offering=TRUE;\r
+               set_sdp_from_desc(invite,h->base.local_media);\r
+       }else h->sdp_offering=FALSE;\r
+       if (h->replaces){\r
+               osip_message_set_header(invite,"Replaces",h->replaces);\r
+               if (h->referred_by)\r
+                       osip_message_set_header(invite,"Referred-By",h->referred_by);\r
+       }\r
+       \r
+       eXosip_lock();\r
+       err=eXosip_call_send_initial_invite(invite);\r
+       eXosip_unlock();\r
+       h->cid=err;\r
+       if (err<0){\r
+               ms_error("Fail to send invite ! Error code %d", err);\r
+               return -1;\r
+       }else{\r
+               char *tmp=NULL;\r
+               callid=osip_message_get_call_id(invite);\r
+               osip_call_id_to_str(callid,&tmp);\r
+               h->base.call_id=ms_strdup(tmp);\r
+               osip_free(tmp);\r
+               sal_add_call(h->base.root,h);\r
+       }\r
+       return 0;\r
+}\r
+\r
+int sal_call_notify_ringing(SalOp *h, bool_t early_media){\r
+       osip_message_t *msg;\r
+       \r
+       /*if early media send also 180 and 183 */\r
+       if (early_media){\r
+               msg=NULL;\r
+               eXosip_lock();\r
+               eXosip_call_build_answer(h->tid,183,&msg);\r
+               if (msg){\r
+                       sdp_process(h);\r
+                       if (h->sdp_answer){\r
+                               set_sdp(msg,h->sdp_answer);\r
+                               sdp_message_free(h->sdp_answer);\r
+                               h->sdp_answer=NULL;\r
+                       }\r
+                       eXosip_call_send_answer(h->tid,183,msg);\r
+               }\r
+               eXosip_unlock();\r
+       }else{\r
+               eXosip_lock();\r
+               eXosip_call_send_answer(h->tid,180,NULL);\r
+               eXosip_unlock();\r
+       }\r
+       return 0;\r
+}\r
+\r
+int sal_call_accept(SalOp * h){\r
+       osip_message_t *msg;\r
+       const char *contact=sal_op_get_contact(h);\r
+       /* sends a 200 OK */\r
+       int err=eXosip_call_build_answer(h->tid,200,&msg);\r
+       if (err<0 || msg==NULL){\r
+               ms_error("Fail to build answer for call: err=%i",err);\r
+               return -1;\r
+       }\r
+       if (h->base.root->session_expires!=0){\r
+               if (h->supports_session_timers) osip_message_set_supported(msg, "timer");\r
+       }\r
+\r
+       if (contact) {\r
+               _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);\r
+               osip_message_set_contact(msg,contact);\r
+       }\r
+       \r
+       if (h->base.local_media){\r
+               /*this is the case where we received an invite without SDP*/\r
+               if (h->sdp_offering) {\r
+                       set_sdp_from_desc(msg,h->base.local_media);\r
+               }else{\r
+                       if (h->sdp_answer==NULL) sdp_process(h);\r
+                       if (h->sdp_answer){\r
+                               set_sdp(msg,h->sdp_answer);\r
+                               sdp_message_free(h->sdp_answer);\r
+                               h->sdp_answer=NULL;\r
+                       }\r
+               }\r
+       }else{\r
+               ms_error("You are accepting a call but not defined any media capabilities !");\r
+       }\r
+       eXosip_call_send_answer(h->tid,200,msg);\r
+       return 0;\r
+}\r
+\r
+int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){\r
+       if (reason==SalReasonBusy){\r
+               eXosip_lock();\r
+               eXosip_call_send_answer(h->tid,486,NULL);\r
+               eXosip_unlock();\r
+       }\r
+       else if (reason==SalReasonTemporarilyUnavailable){\r
+               eXosip_lock();\r
+               eXosip_call_send_answer(h->tid,480,NULL);\r
+               eXosip_unlock();\r
+       }else if (reason==SalReasonDoNotDisturb){\r
+               eXosip_lock();\r
+               eXosip_call_send_answer(h->tid,600,NULL);\r
+               eXosip_unlock();\r
+       }else if (reason==SalReasonMedia){\r
+               eXosip_lock();\r
+               eXosip_call_send_answer(h->tid,415,NULL);\r
+               eXosip_unlock();\r
+       }else if (redirect!=NULL && reason==SalReasonRedirect){\r
+               osip_message_t *msg;\r
+               int code;\r
+               if (strstr(redirect,"sip:")!=0) code=302;\r
+               else code=380;\r
+               eXosip_lock();\r
+               eXosip_call_build_answer(h->tid,code,&msg);\r
+               osip_message_set_contact(msg,redirect);\r
+               eXosip_call_send_answer(h->tid,code,msg);\r
+               eXosip_unlock();\r
+       }else sal_call_terminate(h);\r
+       return 0;\r
+}\r
+\r
+SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){\r
+       return h->base.remote_media;\r
+}\r
+\r
+SalMediaDescription * sal_call_get_final_media_description(SalOp *h){\r
+       if (h->base.local_media && h->base.remote_media && !h->result){\r
+               sdp_process(h);\r
+       }\r
+       return h->result;\r
+}\r
+\r
+int sal_call_set_referer(SalOp *h, SalOp *refered_call){\r
+       if (refered_call->replaces)\r
+               h->replaces=ms_strdup(refered_call->replaces);\r
+       if (refered_call->referred_by)\r
+               h->referred_by=ms_strdup(refered_call->referred_by);\r
+       return 0;\r
+}\r
+\r
+static int send_notify_for_refer(int did, const char *sipfrag){\r
+       osip_message_t *msg;\r
+       eXosip_lock();\r
+       eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);\r
+       if (msg==NULL){\r
+               eXosip_unlock();\r
+               ms_warning("Could not build NOTIFY for refer.");\r
+               return -1;\r
+       }\r
+       osip_message_set_content_type(msg,"message/sipfrag");\r
+       osip_message_set_header(msg,"Event","refer");\r
+       osip_message_set_body(msg,sipfrag,strlen(sipfrag));\r
+       eXosip_call_send_request(did,msg);\r
+       eXosip_unlock();\r
+       return 0;\r
+}\r
+\r
+/* currently only support to notify trying and 200Ok*/\r
+int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){\r
+       if (newcall==NULL){\r
+               /* in progress*/\r
+               send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");\r
+       }\r
+       else if (newcall->cid!=-1){\r
+               if (newcall->did==-1){\r
+                       /* not yet established*/\r
+                       if (!newcall->terminated){\r
+                               /* in progress*/\r
+                               send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n");\r
+                       }\r
+               }else{\r
+                       if (!newcall->terminated){\r
+                               if (send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n")==-1){\r
+                                       /* we need previous notify transaction to complete, so buffer the request for later*/\r
+                                       h->sipfrag_pending="SIP/2.0 200 Ok\r\n";\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+int sal_ping(SalOp *op, const char *from, const char *to){\r
+       osip_message_t *options=NULL;\r
+       \r
+       sal_op_set_from(op,from);\r
+       sal_op_set_to(op,to);\r
+       sal_exosip_fix_route(op);\r
+\r
+       eXosip_options_build_request (&options, sal_op_get_to(op),\r
+                       sal_op_get_from(op),sal_op_get_route(op));\r
+       if (options){\r
+               if (op->base.root->session_expires!=0){\r
+                       osip_message_set_header(options, "Session-expires", "200");\r
+                       osip_message_set_supported(options, "timer");\r
+               }\r
+               sal_add_other(sal_op_get_sal(op),op,options);\r
+               return eXosip_options_send_request(options);\r
+       }\r
+       return -1;\r
+}\r
+\r
+int sal_call_refer(SalOp *h, const char *refer_to){\r
+       osip_message_t *msg=NULL;\r
+       int err=0;\r
+       eXosip_lock();\r
+       eXosip_call_build_refer(h->did,refer_to, &msg);\r
+       if (msg) err=eXosip_call_send_request(h->did, msg);\r
+       else err=-1;\r
+       eXosip_unlock();\r
+       return err;\r
+}\r
+\r
+int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){\r
+       osip_message_t *msg=NULL;\r
+       char referto[256]={0};\r
+       int err=0;\r
+       eXosip_lock();\r
+       if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){\r
+               ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did);\r
+               eXosip_unlock();\r
+               return -1;\r
+       }\r
+       eXosip_call_build_refer(h->did,referto, &msg);\r
+       osip_message_set_header(msg,"Referred-By",h->base.from);\r
+       if (msg) err=eXosip_call_send_request(h->did, msg);\r
+       else err=-1;\r
+       eXosip_unlock();\r
+       return err;\r
+}\r
+\r
+SalOp *sal_call_get_replaces(SalOp *h){\r
+       if (h!=NULL && h->replaces!=NULL){\r
+               int cid;\r
+               eXosip_lock();\r
+               cid=eXosip_call_find_by_replaces(h->replaces);\r
+               eXosip_unlock();\r
+               if (cid>0){\r
+                       SalOp *ret=sal_find_call(h->base.root,cid);\r
+                       return ret;\r
+               }\r
+       }\r
+       return NULL;\r
+}\r
+\r
+int sal_call_send_dtmf(SalOp *h, char dtmf){\r
+       osip_message_t *msg=NULL;\r
+       char dtmf_body[128];\r
+       char clen[10];\r
+\r
+       eXosip_lock();\r
+       eXosip_call_build_info(h->did,&msg);\r
+       if (msg){\r
+               snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf);\r
+               osip_message_set_body(msg,dtmf_body,strlen(dtmf_body));\r
+               osip_message_set_content_type(msg,"application/dtmf-relay");\r
+               snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body));\r
+               osip_message_set_content_length(msg,clen);              \r
+               eXosip_call_send_request(h->did,msg);\r
+       }\r
+       eXosip_unlock();\r
+       return 0;\r
+}\r
+\r
+static void push_auth_to_exosip(const SalAuthInfo *info){\r
+       const char *userid;\r
+       if (info->userid==NULL || info->userid[0]=='\0') userid=info->username;\r
+       else userid=info->userid;\r
+       ms_message("Authentication info for username [%s], id[%s], realm [%s] added to eXosip", info->username,userid, info->realm);\r
+       eXosip_add_authentication_info (info->username,userid,\r
+                                  info->password, NULL,info->realm);\r
+}\r
+/*\r
+ * Just for symmetry ;-)\r
+ */\r
+static void pop_auth_from_exosip() {\r
+       eXosip_clear_authentication_info();\r
+}\r
+\r
+int sal_call_terminate(SalOp *h){\r
+       int err;\r
+       if (h == NULL) return -1;\r
+       if (h->auth_info) push_auth_to_exosip(h->auth_info);\r
+       eXosip_lock();\r
+       err=eXosip_call_terminate(h->cid,h->did);\r
+       eXosip_unlock();\r
+       if (!h->base.root->reuse_authorization) pop_auth_from_exosip();\r
+       if (err!=0){\r
+               ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did);\r
+       }\r
+       h->terminated=TRUE;\r
+       return 0;\r
+}\r
+\r
+void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){\r
+       bool_t terminating=FALSE;\r
+       if (h->pending_auth && strcmp(h->pending_auth->request->sip_method,"BYE")==0) {\r
+               terminating=TRUE;\r
+       }\r
+       if (h->terminated && !terminating) return;\r
+\r
+       if (h->pending_auth){\r
+               push_auth_to_exosip(info);\r
+               \r
+        /*FIXME exosip does not take into account this update register message*/\r
+       /*\r
+        if (fix_message_contact(h, h->pending_auth->request,h->pending_auth->response)) {\r
+            \r
+        };\r
+       */\r
+               update_contact_from_response(h,h->pending_auth->response);\r
+               eXosip_lock();\r
+               eXosip_default_action(h->pending_auth);\r
+               eXosip_unlock();\r
+               ms_message("eXosip_default_action() done");\r
+               if (!h->base.root->reuse_authorization) pop_auth_from_exosip();\r
+               \r
+               if (h->auth_info) sal_auth_info_delete(h->auth_info); /*if already exist*/\r
+               h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/\r
+       }\r
+}\r
+void sal_op_cancel_authentication(SalOp *h) {\r
+       if (h->rid >0) {\r
+               sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure");\r
+       } else if (h->cid >0) {\r
+               sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0);\r
+       } else {\r
+               ms_warning("Auth failure not handled");\r
+       }\r
+\r
+}\r
+static void set_network_origin(SalOp *op, osip_message_t *req){\r
+       const char *received=NULL;\r
+       int rport=5060;\r
+       char origin[64]={0};\r
+    SalTransport transport;\r
+       if (extract_received_rport(req,&received,&rport,&transport)!=0){\r
+               osip_via_t *via=NULL;\r
+               char *tmp;\r
+               osip_message_get_via(req,0,&via);\r
+               received=osip_via_get_host(via);\r
+               tmp=osip_via_get_port(via);\r
+               if (tmp) rport=atoi(tmp);\r
+       }\r
+    if (transport != SalTransportUDP) {\r
+        snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport);\r
+    } else {\r
+       snprintf(origin,sizeof(origin)-1,"sip:%s:%i;transport=%s",received,rport,sal_transport_to_string(transport)); \r
+    }\r
+       __sal_op_set_network_origin(op,origin);\r
+}\r
+\r
+static void set_remote_ua(SalOp* op, osip_message_t *req){\r
+       if (op->base.remote_ua==NULL){\r
+               osip_header_t *h=NULL;\r
+               osip_message_get_user_agent(req,0,&h);\r
+               if (h){\r
+                       op->base.remote_ua=ms_strdup(h->hvalue);\r
+               }\r
+       }\r
+}\r
+\r
+static void set_remote_contact(SalOp* op, osip_message_t *req){\r
+       if (op->base.remote_contact==NULL){\r
+               osip_contact_t *h=NULL;\r
+               osip_message_get_contact(req,0,&h);\r
+               if (h){\r
+                       char *tmp=NULL;\r
+                       osip_contact_to_str(h,&tmp);\r
+                       __sal_op_set_remote_contact(op,tmp);\r
+                       osip_free(tmp);\r
+               }\r
+       }\r
+}\r
+\r
+static void set_replaces(SalOp *op, osip_message_t *req){\r
+       osip_header_t *h=NULL;\r
+\r
+       if (op->replaces){\r
+               ms_free(op->replaces);\r
+               op->replaces=NULL;\r
+       }\r
+       osip_message_header_get_byname(req,"replaces",0,&h);\r
+       if (h){\r
+               if (h->hvalue && h->hvalue[0]!='\0'){\r
+                       op->replaces=ms_strdup(h->hvalue);\r
+               }\r
+       }\r
+}\r
+\r
+static SalOp *find_op(Sal *sal, eXosip_event_t *ev){\r
+       if (ev->cid>0){\r
+               return sal_find_call(sal,ev->cid);\r
+       }\r
+       if (ev->rid>0){\r
+               return sal_find_register(sal,ev->rid);\r
+       }\r
+       if (ev->sid>0){\r
+               return sal_find_out_subscribe(sal,ev->sid);\r
+       }\r
+       if (ev->nid>0){\r
+               return sal_find_in_subscribe(sal,ev->nid);\r
+       }\r
+       if (ev->response) return sal_find_other(sal,ev->response);\r
+       else if (ev->request) return sal_find_other(sal,ev->request);\r
+       return NULL;\r
+}\r
+\r
+static void inc_new_call(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op=sal_op_new(sal);\r
+       osip_from_t *from,*to;\r
+       osip_call_info_t *call_info;\r
+       char *tmp=NULL;\r
+       sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);\r
+       \r
+       osip_call_id_t *callid=osip_message_get_call_id(ev->request);\r
+       \r
+       osip_call_id_to_str(callid,&tmp);\r
+       op->base.call_id=ms_strdup(tmp);\r
+       osip_free(tmp);\r
+       \r
+       set_network_origin(op,ev->request);\r
+       set_remote_contact(op,ev->request);\r
+       set_remote_ua(op,ev->request);\r
+       set_replaces(op,ev->request);\r
+       sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request));\r
+       \r
+       if (sdp){\r
+               op->sdp_offering=FALSE;\r
+               op->base.remote_media=sal_media_description_new();\r
+               sdp_to_media_description(sdp,op->base.remote_media);\r
+               sdp_message_free(sdp);\r
+       }else op->sdp_offering=TRUE;\r
+\r
+       from=osip_message_get_from(ev->request);\r
+       to=osip_message_get_to(ev->request);\r
+       osip_from_to_str(from,&tmp);\r
+       sal_op_set_from(op,tmp);\r
+       osip_free(tmp);\r
+       osip_from_to_str(to,&tmp);\r
+       sal_op_set_to(op,tmp);\r
+       osip_free(tmp);\r
+\r
+       osip_message_get_call_info(ev->request,0,&call_info);\r
+       if(call_info)\r
+       {\r
+               osip_call_info_to_str(call_info,&tmp);\r
+               if( strstr(tmp,"answer-after=") != NULL)\r
+               {\r
+                       op->auto_answer_asked=TRUE;\r
+                       ms_message("The caller asked to automatically answer the call(Emergency?)\n");\r
+               }\r
+               osip_free(tmp);\r
+       }\r
+\r
+       op->tid=ev->tid;\r
+       op->cid=ev->cid;\r
+       op->did=ev->did;\r
+       sal_add_call(op->base.root,op);\r
+       sal->callbacks.call_received(op);\r
+}\r
+\r
+static void handle_reinvite(Sal *sal,  eXosip_event_t *ev){\r
+       SalOp *op=find_op(sal,ev);\r
+       sdp_message_t *sdp;\r
+\r
+       if (op==NULL) {\r
+               ms_warning("Reinvite for non-existing operation !");\r
+               return;\r
+       }\r
+       op->reinvite=TRUE;\r
+       op->tid=ev->tid;\r
+       sdp=eXosip_get_sdp_info(ev->request);\r
+       if (op->base.remote_media){\r
+               sal_media_description_unref(op->base.remote_media);\r
+               op->base.remote_media=NULL;\r
+       }\r
+       if (op->result){\r
+               sal_media_description_unref(op->result);\r
+               op->result=NULL;\r
+       }\r
+       if (sdp){\r
+               op->sdp_offering=FALSE;\r
+               op->base.remote_media=sal_media_description_new();\r
+               sdp_to_media_description(sdp,op->base.remote_media);\r
+               sdp_message_free(sdp);\r
+               \r
+       }else {\r
+               op->sdp_offering=TRUE;\r
+       }\r
+       sal->callbacks.call_updating(op);\r
+}\r
+\r
+static void handle_ack(Sal *sal,  eXosip_event_t *ev){\r
+       SalOp *op=find_op(sal,ev);\r
+       sdp_message_t *sdp;\r
+\r
+       if (op==NULL) {\r
+               ms_warning("ack for non-existing call !");\r
+               return;\r
+       }\r
+       if (op->terminated) {\r
+               ms_warning("ack for terminated call, ignoring");\r
+               return;\r
+       }\r
+       \r
+       if (op->sdp_offering){\r
+               sdp=eXosip_get_sdp_info(ev->ack);\r
+               if (sdp){\r
+                       if (op->base.remote_media)\r
+                               sal_media_description_unref(op->base.remote_media);\r
+                       op->base.remote_media=sal_media_description_new();\r
+                       sdp_to_media_description(sdp,op->base.remote_media);\r
+                       sdp_process(op);\r
+                       sdp_message_free(sdp);\r
+               }\r
+       }\r
+       if (op->reinvite){\r
+               op->reinvite=FALSE;\r
+       }\r
+       sal->callbacks.call_ack(op);\r
+}\r
+\r
+static void update_contact_from_response(SalOp *op, osip_message_t *response){\r
+       const char *received;\r
+       int rport;\r
+       SalTransport transport;\r
+       if (extract_received_rport(response,&received,&rport,&transport)==0){\r
+               const char *contact=sal_op_get_contact(op);\r
+               if (!contact){\r
+                       /*no contact given yet, use from instead*/\r
+                       contact=sal_op_get_from(op);\r
+               }\r
+               if (contact){\r
+                       SalAddress *addr=sal_address_new(contact);\r
+                       char *tmp;\r
+                       sal_address_set_domain(addr,received);\r
+                       sal_address_set_port_int(addr,rport);\r
+                       if (transport!=SalTransportUDP)\r
+                               sal_address_set_transport(addr,transport);\r
+                       tmp=sal_address_as_string(addr);\r
+                       ms_message("Contact address updated to %s",tmp);\r
+                       sal_op_set_contact(op,tmp);\r
+                       sal_address_destroy(addr);\r
+                       ms_free(tmp);\r
+               }\r
+       }\r
+}\r
+\r
+static int call_proceeding(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op=find_op(sal,ev);\r
+\r
+       if (op==NULL || op->terminated==TRUE) {\r
+               ms_warning("This call has been canceled.");\r
+               eXosip_lock();\r
+               eXosip_call_terminate(ev->cid,ev->did);\r
+               eXosip_unlock();\r
+               return -1;\r
+       }\r
+       if (ev->did>0)\r
+               op->did=ev->did;\r
+       op->tid=ev->tid;\r
+       \r
+       /* update contact if received and rport are set by the server\r
+        note: will only be used by remote for next INVITE, if any...*/\r
+       update_contact_from_response(op,ev->response);\r
+       return 0;\r
+}\r
+\r
+static void call_ringing(Sal *sal, eXosip_event_t *ev){\r
+       sdp_message_t *sdp;\r
+       SalOp *op=find_op(sal,ev);\r
+       if (call_proceeding(sal, ev)==-1) return;\r
+\r
+       set_remote_ua(op,ev->response);\r
+       sdp=eXosip_get_sdp_info(ev->response);\r
+       if (sdp){\r
+               op->base.remote_media=sal_media_description_new();\r
+               sdp_to_media_description(sdp,op->base.remote_media);\r
+               sdp_message_free(sdp);\r
+               if (op->base.local_media) sdp_process(op);\r
+       }\r
+       sal->callbacks.call_ringing(op);\r
+}\r
+\r
+static void call_accepted(Sal *sal, eXosip_event_t *ev){\r
+       sdp_message_t *sdp;\r
+       osip_message_t *msg=NULL;\r
+       SalOp *op=find_op(sal,ev);\r
+       const char *contact;\r
+       \r
+       if (op==NULL || op->terminated==TRUE) {\r
+               ms_warning("This call has been already terminated.");\r
+               eXosip_lock();\r
+               eXosip_call_terminate(ev->cid,ev->did);\r
+               eXosip_unlock();\r
+               return ;\r
+       }\r
+\r
+       op->did=ev->did;\r
+       set_remote_ua(op,ev->response);\r
+       set_remote_contact(op,ev->response);\r
+\r
+       sdp=eXosip_get_sdp_info(ev->response);\r
+       if (sdp){\r
+               op->base.remote_media=sal_media_description_new();\r
+               sdp_to_media_description(sdp,op->base.remote_media);\r
+               sdp_message_free(sdp);\r
+               if (op->base.local_media) sdp_process(op);\r
+       }\r
+       eXosip_call_build_ack(ev->did,&msg);\r
+       if (msg==NULL) {\r
+               ms_warning("This call has been already terminated.");\r
+               eXosip_lock();\r
+               eXosip_call_terminate(ev->cid,ev->did);\r
+               eXosip_unlock();\r
+               return ;\r
+       }\r
+       contact=sal_op_get_contact(op);\r
+       if (contact) {\r
+               _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);\r
+               osip_message_set_contact(msg,contact);\r
+       }\r
+       if (op->sdp_answer){\r
+               set_sdp(msg,op->sdp_answer);\r
+               sdp_message_free(op->sdp_answer);\r
+               op->sdp_answer=NULL;\r
+       }\r
+       eXosip_call_send_ack(ev->did,msg);\r
+       sal->callbacks.call_accepted(op);\r
+}\r
+\r
+static void call_terminated(Sal *sal, eXosip_event_t *ev){\r
+       char *from=NULL;\r
+       SalOp *op=find_op(sal,ev);\r
+       if (op==NULL){\r
+               ms_warning("Call terminated for already closed call ?");\r
+               return;\r
+       }\r
+       if (ev->request){\r
+               osip_from_to_str(ev->request->from,&from);\r
+       }\r
+       sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op));\r
+       if (from) osip_free(from);\r
+       op->terminated=TRUE;\r
+}\r
+\r
+static void call_released(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op=find_op(sal,ev);\r
+       if (op==NULL){\r
+               ms_warning("No op associated to this call_released()");\r
+               return;\r
+       }\r
+       if (!op->terminated){\r
+               /* no response received so far */\r
+               call_failure(sal,ev);\r
+       }\r
+       sal->callbacks.call_released(op);\r
+}\r
+\r
+static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){\r
+       const char *prx_realm=NULL,*www_realm=NULL;\r
+       osip_proxy_authenticate_t *prx_auth;\r
+       osip_www_authenticate_t *www_auth;\r
+       \r
+       *username=osip_uri_get_username(resp->from->url);\r
+       prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0);\r
+       www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0);\r
+       if (prx_auth!=NULL)\r
+               prx_realm=osip_proxy_authenticate_get_realm(prx_auth);\r
+       if (www_auth!=NULL)\r
+               www_realm=osip_www_authenticate_get_realm(www_auth);\r
+\r
+       if (prx_realm){\r
+               *realm=prx_realm;\r
+       }else if (www_realm){\r
+               *realm=www_realm;\r
+       }else{\r
+               return -1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+static int get_auth_data_from_request(osip_message_t *msg, const char **realm, const char **username){\r
+       osip_authorization_t *auth=NULL;\r
+       osip_proxy_authorization_t *prx_auth=NULL;\r
+       \r
+       *username=osip_uri_get_username(msg->from->url);\r
+       osip_message_get_authorization(msg, 0, &auth);\r
+       if (auth){\r
+               *realm=osip_authorization_get_realm(auth);\r
+               return 0;\r
+       }\r
+       osip_message_get_proxy_authorization(msg,0,&prx_auth);\r
+       if (prx_auth){\r
+               *realm=osip_proxy_authorization_get_realm(prx_auth);\r
+               return 0;\r
+       }\r
+       return -1;\r
+}\r
+\r
+static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){\r
+       if (ev->response && get_auth_data_from_response(ev->response,realm,username)==0) return 0;\r
+       if (ev->request && get_auth_data_from_request(ev->request,realm,username)==0) return 0;\r
+       return -1;\r
+}\r
+\r
+int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){\r
+       if (op->pending_auth){\r
+               return get_auth_data(op->pending_auth,realm,username);\r
+       }\r
+       return -1;\r
+}\r
+\r
+static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op;\r
+       const char *username,*realm;\r
+       op=find_op(sal,ev);\r
+       if (op==NULL){\r
+               ms_warning("No operation associated with this authentication !");\r
+               return TRUE;\r
+       }\r
+       if (get_auth_data(ev,&realm,&username)==0){\r
+               if (op->pending_auth!=NULL){\r
+                       eXosip_event_free(op->pending_auth);\r
+                       op->pending_auth=ev;\r
+               }else{\r
+                       op->pending_auth=ev;\r
+                       sal_add_pending_auth(sal,op);\r
+               }\r
+               \r
+               sal->callbacks.auth_requested(op,realm,username);\r
+               return FALSE;\r
+       }\r
+       return TRUE;\r
+}\r
+\r
+static void authentication_ok(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op;\r
+       const char *username,*realm;\r
+       op=find_op(sal,ev);\r
+       if (op==NULL){\r
+               ms_warning("No operation associated with this authentication_ok!");\r
+               return ;\r
+       }\r
+       if (op->pending_auth){\r
+               eXosip_event_free(op->pending_auth);\r
+               sal_remove_pending_auth(sal,op);\r
+               op->pending_auth=NULL;\r
+       }\r
+       if (get_auth_data(ev,&realm,&username)==0){\r
+               sal->callbacks.auth_success(op,realm,username);\r
+       }\r
+}\r
+\r
+static bool_t call_failure(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op;\r
+       int code=0;\r
+       char* computedReason=NULL;\r
+       const char *reason=NULL;\r
+       SalError error=SalErrorUnknown;\r
+       SalReason sr=SalReasonUnknown;\r
+       \r
+\r
+       op=(SalOp*)find_op(sal,ev);\r
+\r
+       if (op==NULL) {\r
+               ms_warning("Call failure reported for a closed call, ignored.");\r
+               return TRUE;\r
+       }\r
+\r
+       if (ev->response){\r
+               code=osip_message_get_status_code(ev->response);\r
+               reason=osip_message_get_reason_phrase(ev->response);\r
+               osip_header_t *h=NULL;\r
+               if (!osip_message_header_get_byname(    ev->response\r
+                                                                                       ,"Reason"\r
+                                                                                       ,0\r
+                                                                                       ,&h)) {\r
+                       computedReason = ms_strdup_printf("%s %s",reason,osip_header_get_value(h));\r
+                       reason = computedReason;\r
+\r
+               }\r
+       }\r
+       switch(code)\r
+       {\r
+               case 401:\r
+               case 407:\r
+                       return process_authentication(sal,ev);\r
+                       break;\r
+               case 400:\r
+                       error=SalErrorUnknown;\r
+               break;\r
+               case 404:\r
+                       error=SalErrorFailure;\r
+                       sr=SalReasonNotFound;\r
+               break;\r
+               case 415:\r
+                       error=SalErrorFailure;\r
+                       sr=SalReasonMedia;\r
+               break;\r
+               case 422:\r
+                       eXosip_default_action(ev);\r
+                       return TRUE;\r
+               break;\r
+               case 480:\r
+                       error=SalErrorFailure;\r
+                       sr=SalReasonTemporarilyUnavailable;\r
+               case 486:\r
+                       error=SalErrorFailure;\r
+                       sr=SalReasonBusy;\r
+               break;\r
+               case 487:\r
+               break;\r
+               case 600:\r
+                       error=SalErrorFailure;\r
+                       sr=SalReasonDoNotDisturb;\r
+               break;\r
+               case 603:\r
+                       error=SalErrorFailure;\r
+                       sr=SalReasonDeclined;\r
+               break;\r
+               default:\r
+                       if (code>0){\r
+                               error=SalErrorFailure;\r
+                               sr=SalReasonUnknown;\r
+                       }else error=SalErrorNoResponse;\r
+       }\r
+       op->terminated=TRUE;\r
+       sal->callbacks.call_failure(op,error,sr,reason,code);\r
+       if (computedReason != NULL){\r
+               ms_free(computedReason);\r
+       }\r
+       return TRUE;\r
+}\r
+\r
+/* Request remote side to send us VFU */\r
+void sal_call_send_vfu_request(SalOp *h){\r
+       osip_message_t *msg=NULL;\r
+       char info_body[] =\r
+                       "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"\r
+                        "<media_control>"\r
+                        "  <vc_primitive>"\r
+                        "    <to_encoder>"\r
+                        "      <picture_fast_update></picture_fast_update>"\r
+                        "    </to_encoder>"\r
+                        "  </vc_primitive>"\r
+                        "</media_control>";\r
+\r
+       char clen[10];\r
+\r
+       eXosip_lock();\r
+       eXosip_call_build_info(h->did,&msg);\r
+       if (msg){\r
+               osip_message_set_body(msg,info_body,strlen(info_body));\r
+               osip_message_set_content_type(msg,"application/media_control+xml");\r
+               snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(info_body));\r
+               osip_message_set_content_length(msg,clen);\r
+               eXosip_call_send_request(h->did,msg);\r
+               ms_message("Sending VFU request !");\r
+       }\r
+       eXosip_unlock();\r
+}\r
+\r
+static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op=find_op(sal,ev);\r
+       osip_body_t *body=NULL;\r
+\r
+       if (op==NULL){\r
+               ms_warning("media control xml received without operation context!");\r
+               return ;\r
+       }\r
+       \r
+       osip_message_get_body(ev->request,0,&body);\r
+       if (body && body->body!=NULL &&\r
+               strstr(body->body,"picture_fast_update")){\r
+               osip_message_t *ans=NULL;\r
+               ms_message("Receiving VFU request !");\r
+               if (sal->callbacks.vfu_request){\r
+                       sal->callbacks.vfu_request(op);\r
+                       eXosip_call_build_answer(ev->tid,200,&ans);\r
+                       if (ans)\r
+                               eXosip_call_send_answer(ev->tid,200,ans);\r
+                       return;\r
+               }\r
+       }\r
+       /*in all other cases we must say it is not implemented.*/\r
+       {\r
+               osip_message_t *ans=NULL;\r
+               eXosip_lock();\r
+               eXosip_call_build_answer(ev->tid,501,&ans);\r
+               if (ans)\r
+                       eXosip_call_send_answer(ev->tid,501,ans);\r
+               eXosip_unlock();\r
+       }\r
+}\r
+\r
+static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op=find_op(sal,ev);\r
+       osip_body_t *body=NULL;\r
+\r
+       if (op==NULL){\r
+               ms_warning("media dtmf relay received without operation context!");\r
+               return ;\r
+       }\r
+       \r
+       osip_message_get_body(ev->request,0,&body);\r
+       if (body && body->body!=NULL){\r
+               osip_message_t *ans=NULL;\r
+               const char *name=strstr(body->body,"Signal");\r
+               if (name==NULL) name=strstr(body->body,"signal");\r
+               if (name==NULL) {\r
+                       ms_warning("Could not extract the dtmf name from the SIP INFO.");\r
+               }else{\r
+                       char tmp[2];\r
+                       name+=strlen("signal");\r
+                       if (sscanf(name," = %1s",tmp)==1){\r
+                               ms_message("Receiving dtmf %s via SIP INFO.",tmp);\r
+                               if (sal->callbacks.dtmf_received != NULL)\r
+                                       sal->callbacks.dtmf_received(op, tmp[0]);\r
+                       }\r
+               }\r
+               eXosip_lock();\r
+               eXosip_call_build_answer(ev->tid,200,&ans);\r
+               if (ans)\r
+                       eXosip_call_send_answer(ev->tid,200,ans);\r
+               eXosip_unlock();\r
+       }\r
+}\r
+\r
+static void fill_options_answer(osip_message_t *options){\r
+       osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO");\r
+       osip_message_set_accept(options,"application/sdp");\r
+}\r
+\r
+static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){\r
+       osip_header_t *h=NULL;\r
+       osip_message_t *ans=NULL;\r
+       ms_message("Receiving REFER request !");\r
+       osip_message_header_get_byname(ev->request,"Refer-To",0,&h);\r
+\r
+       if (h){\r
+               osip_from_t *from=NULL;\r
+               char *tmp;\r
+               osip_from_init(&from);\r
+       \r
+               if (osip_from_parse(from,h->hvalue)==0){\r
+                       if (op ){\r
+                               osip_uri_header_t *uh=NULL;\r
+                               osip_header_t *referred_by=NULL;\r
+                               osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh);\r
+                               if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){\r
+                                       ms_message("Found replaces in Refer-To");\r
+                                       if (op->replaces){\r
+                                               ms_free(op->replaces);\r
+                                       }\r
+                                       op->replaces=ms_strdup(uh->gvalue);\r
+                               }\r
+                               osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by);\r
+                               if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){\r
+                                       if (op->referred_by)\r
+                                               ms_free(op->referred_by);\r
+                                       op->referred_by=ms_strdup(referred_by->hvalue);\r
+                               }\r
+                       }\r
+                       osip_uri_header_freelist(&from->url->url_headers);\r
+                       osip_from_to_str(from,&tmp);\r
+                       sal->callbacks.refer_received(sal,op,tmp);\r
+                       osip_free(tmp);\r
+                       osip_from_free(from);\r
+               }\r
+               eXosip_lock();\r
+               eXosip_call_build_answer(ev->tid,202,&ans);\r
+               if (ans)\r
+                       eXosip_call_send_answer(ev->tid,202,ans);\r
+               eXosip_unlock();\r
+       }\r
+       else\r
+       {\r
+               ms_warning("cannot do anything with the refer without destination\n");\r
+       }\r
+}\r
+\r
+static void process_notify(Sal *sal, eXosip_event_t *ev){\r
+       osip_header_t *h=NULL;\r
+       char *from=NULL;\r
+       SalOp *op=find_op(sal,ev);\r
+       osip_message_t *ans=NULL;\r
+\r
+       ms_message("Receiving NOTIFY request !");\r
+       osip_from_to_str(ev->request->from,&from);\r
+       osip_message_header_get_byname(ev->request,"Event",0,&h);\r
+       if(h){\r
+               osip_body_t *body=NULL;\r
+               //osip_content_type_t *ct=NULL;\r
+               osip_message_get_body(ev->request,0,&body);\r
+               //ct=osip_message_get_content_type(ev->request);\r
+               if (h->hvalue && strcasecmp(h->hvalue,"refer")==0){\r
+                       /*special handling of refer events*/\r
+                       if (body && body->body){\r
+                               osip_message_t *msg;\r
+                               osip_message_init(&msg);\r
+                               if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){\r
+                                       int code=osip_message_get_status_code(msg);\r
+                                       if (code==100){\r
+                                               sal->callbacks.notify_refer(op,SalReferTrying);\r
+                                       }else if (code==200){\r
+                                               sal->callbacks.notify_refer(op,SalReferSuccess);\r
+                                       }else if (code>=400){\r
+                                               sal->callbacks.notify_refer(op,SalReferFailed);\r
+                                       }\r
+                               }\r
+                               osip_message_free(msg);\r
+                       }\r
+               }else{\r
+                       /*generic handling*/\r
+                       sal->callbacks.notify(op,from,h->hvalue);\r
+               }\r
+       }\r
+       /*answer that we received the notify*/\r
+       eXosip_lock();\r
+       eXosip_call_build_answer(ev->tid,200,&ans);\r
+       if (ans)\r
+               eXosip_call_send_answer(ev->tid,200,ans);\r
+       eXosip_unlock();\r
+       osip_free(from);\r
+}\r
+\r
+static void call_message_new(Sal *sal, eXosip_event_t *ev){\r
+       osip_message_t *ans=NULL;\r
+       if (ev->request){\r
+               if (MSG_IS_INFO(ev->request)){\r
+                       osip_content_type_t *ct;\r
+                       ct=osip_message_get_content_type(ev->request);\r
+                       if (ct && ct->subtype){\r
+                               if (strcmp(ct->subtype,"media_control+xml")==0)\r
+                                       process_media_control_xml(sal,ev);\r
+                               else if (strcmp(ct->subtype,"dtmf-relay")==0)\r
+                                       process_dtmf_relay(sal,ev);\r
+                               else {\r
+                                       ms_message("Unhandled SIP INFO.");\r
+                                       /*send an "Not implemented" answer*/\r
+                                       eXosip_lock();\r
+                                       eXosip_call_build_answer(ev->tid,501,&ans);\r
+                                       if (ans)\r
+                                               eXosip_call_send_answer(ev->tid,501,ans);\r
+                                       eXosip_unlock();\r
+                               }\r
+                       }else{\r
+                               /*empty SIP INFO, probably to test we are alive. Send an empty answer*/\r
+                               eXosip_lock();\r
+                               eXosip_call_build_answer(ev->tid,200,&ans);\r
+                               if (ans)\r
+                                       eXosip_call_send_answer(ev->tid,200,ans);\r
+                               eXosip_unlock();\r
+                       }\r
+               }else if(MSG_IS_MESSAGE(ev->request)){\r
+                       /* SIP messages could be received into call */\r
+                       text_received(sal, ev);\r
+                       eXosip_lock();\r
+                       eXosip_call_build_answer(ev->tid,200,&ans);\r
+                       if (ans)\r
+                               eXosip_call_send_answer(ev->tid,200,ans);\r
+                       eXosip_unlock();\r
+               }else if(MSG_IS_REFER(ev->request)){\r
+                       SalOp *op=find_op(sal,ev);\r
+                       \r
+                       ms_message("Receiving REFER request !");\r
+                       process_refer(sal,op,ev);\r
+               }else if(MSG_IS_NOTIFY(ev->request)){\r
+                       process_notify(sal,ev);\r
+               }else if (MSG_IS_OPTIONS(ev->request)){\r
+                       eXosip_lock();\r
+                       eXosip_call_build_answer(ev->tid,200,&ans);\r
+                       if (ans){\r
+                               fill_options_answer(ans);\r
+                               eXosip_call_send_answer(ev->tid,200,ans);\r
+                       }\r
+                       eXosip_unlock();\r
+               }\r
+       }else ms_warning("call_message_new: No request ?");\r
+}\r
+\r
+static void inc_update(Sal *sal, eXosip_event_t *ev){\r
+       osip_message_t *msg=NULL;\r
+       ms_message("Processing incoming UPDATE");\r
+       eXosip_lock();\r
+       eXosip_message_build_answer(ev->tid,200,&msg);\r
+       if (msg!=NULL)\r
+               eXosip_message_send_answer(ev->tid,200,msg);\r
+       eXosip_unlock();\r
+}\r
+\r
+static bool_t comes_from_local_if(osip_message_t *msg){\r
+       osip_via_t *via=NULL;\r
+       osip_message_get_via(msg,0,&via);\r
+       if (via){\r
+               const char *host;\r
+               host=osip_via_get_host(via);\r
+               if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){\r
+                       osip_generic_param_t *param=NULL;\r
+                       osip_via_param_get_byname(via,"received",&param);\r
+                       if (param==NULL) return TRUE;\r
+                       if (param->gvalue &&\r
+                               (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){\r
+                               return TRUE;\r
+                       }\r
+               }\r
+       }\r
+       return FALSE;\r
+}\r
+\r
 static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};\r
-static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
-
-static void text_received(Sal *sal, eXosip_event_t *ev){
-       osip_body_t *body=NULL;
-       char *from=NULL,*msg=NULL;
-       osip_content_type_t* content_type;
-       osip_uri_param_t* external_body_url; 
-       char unquoted_external_body_url [256];
-       int external_body_size=0;
-       SalMessage salmsg;
-       char message_id[256]={0};
-       osip_header_t *date=NULL;
-       struct tm ret={};
-       char tmp1[80]={0};
-       char tmp2[80]={0};
-       int i,j;
-
-       osip_message_get_date(ev->request,0,&date);
-       if(date==NULL){
-               ms_error("Could not get the date of message");
-               return;
-       }
-       sscanf(date->hvalue,"%3c,%d%s%d%d:%d:%d",tmp1,&ret.tm_mday,tmp2,
-                    &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec);
-       ret.tm_year-=1900;
-       for(i=0;i<7;i++) { 
-               if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; 
-       }
-       for(j=0;j<12;j++) { 
-               if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; 
-       }
-       
-       content_type= osip_message_get_content_type(ev->request);
-       if (!content_type) {
-               ms_error("Could not get message because no content type");
-               return;
-       }
-       osip_from_to_str(ev->request->from,&from);
-       if (content_type->type 
-               && strcmp(content_type->type, "text")==0 
-               && content_type->subtype
-               && strcmp(content_type->subtype, "plain")==0 ) {
-               osip_message_get_body(ev->request,0,&body);
-               if (body==NULL){
-                       ms_error("Could not get text message from SIP body");
-                       osip_free(from);
-                       return;
-               }
-               msg=body->body;
-       }else if (content_type->type 
-                 && strcmp(content_type->type, "message")==0 
-                 && content_type->subtype
-                 && strcmp(content_type->subtype, "external-body")==0 ) {
-               
-               osip_content_type_param_get_byname(content_type, "URL", &external_body_url);
-               /*remove both first and last character*/
-               strncpy(unquoted_external_body_url
-                               ,&external_body_url->gvalue[1]
-                               ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url)));
-               unquoted_external_body_url[external_body_size-1]='\0';
-       } else {
-               ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype);
-               osip_free(from);
-               return;
-       }
-       snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number);
-       
-       salmsg.from=from;
-       salmsg.text=msg;
-       salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL;
-       salmsg.message_id=message_id;
-       salmsg.time=mktime(&ret);
-       sal->callbacks.text_received(sal,&salmsg);
-       osip_free(from);
-}
-
-
-
-static void other_request(Sal *sal, eXosip_event_t *ev){
-       ms_message("in other_request");
-       if (ev->request==NULL) return;
-       if (strcmp(ev->request->sip_method,"MESSAGE")==0){
-               text_received(sal,ev);
-               eXosip_message_send_answer(ev->tid,200,NULL);
-       }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){
-               osip_message_t *options=NULL;
-               eXosip_options_build_answer(ev->tid,200,&options);
-               fill_options_answer(options);
-               eXosip_options_send_answer(ev->tid,200,options);
-       }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){
-               ms_message("Receiving REFER request !");
-               if (comes_from_local_if(ev->request)) {
-                       process_refer(sal,NULL,ev);
-               }else ms_warning("Ignored REFER not coming from this local loopback interface.");
-       }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){
-               inc_update(sal,ev);
-       }else {
-               char *tmp=NULL;
-               size_t msglen=0;
-               osip_message_to_str(ev->request,&tmp,&msglen);
-               if (tmp){
-                       ms_message("Unsupported request received:\n%s",tmp);
-                       osip_free(tmp);
-               }
-               /*answer with a 501 Not implemented*/
-               eXosip_message_send_answer(ev->tid,501,NULL);
-       }
-}
-
-static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){
-       osip_via_t *via=NULL;
-       osip_message_get_via(msg,0,&via);
-       if (via){
-               osip_free(via->port);
-               via->port=osip_strdup(port);
-               osip_free(via->host);
-               via->host=osip_strdup(ip);
-       }
-}
-
-
-static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) {
-       osip_contact_t *ctt=NULL;
-       const char *received;
-       int rport;
-       SalTransport transport;
-       char port[20];
-
-       if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;
-       osip_message_get_contact(request,0,&ctt);
-       if (ctt == NULL) {
-               ms_warning("fix_message_contact(): no contact to update");
-               return FALSE;
-       }
-       if (expire_last_contact){
-               osip_contact_t *oldct=NULL,*prevct;
-               osip_generic_param_t *param=NULL;
-               osip_contact_clone(ctt,&oldct);
-               while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){
-                       osip_contact_free(prevct);
-                       osip_list_remove(&request->contacts,1);
-               }
-               osip_list_add(&request->contacts,oldct,1);
-               osip_contact_param_get_byname(oldct,"expires",&param);
-               if (param){
-                       if (param->gvalue) osip_free(param->gvalue);
-                       param->gvalue=osip_strdup("0");
-               }else{
-                       osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0"));
-               }
-       }
-       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);
-       }
-       snprintf(port,sizeof(port),"%i",rport);
-       ctt->url->port=osip_strdup(port);
-       if (op->masquerade_via) masquerade_via(request,received,port);
-
-       if (transport != SalTransportUDP) {
-               sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport)); 
-       }
-       return TRUE;    
-}
-
-static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){
-       osip_contact_t *ctt=NULL;
-       SalAddress* ori_contact_address=NULL;
-       const char *received;
-       int rport;
-       SalTransport transport;
-       char* tmp;
-       osip_message_t *msg=NULL;
-       Sal* sal=op->base.root;
-       int i=0;
-       bool_t found_valid_contact=FALSE;
-       bool_t from_request=FALSE;
-
-       if (sal->double_reg==FALSE ) return FALSE; 
-
-       if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;
-       do{
-               ctt=NULL;
-               osip_message_get_contact(last_answer,i,&ctt);
-               if (!from_request && ctt==NULL) {
-                       osip_message_get_contact(orig_request,0,&ctt);
-                       from_request=TRUE;
-               }
-               if (ctt){
-                       osip_contact_to_str(ctt,&tmp);
-                       ori_contact_address = sal_address_new(tmp);
-       
-                       /*check if contact is up to date*/
-                       if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0 
-                               && sal_address_get_port_int(ori_contact_address) == rport
-                       && sal_address_get_transport(ori_contact_address) == transport) {
-                               if (!from_request){
-                                       ms_message("Register response has up to date contact, doing nothing.");
-                               }else {
-                                       ms_warning("Register response does not have up to date contact, but last request had."
-                                               "Stupid registrar detected, giving up.");
-                               }
-                               found_valid_contact=TRUE;
-                       }
-                       osip_free(tmp);
-                       sal_address_destroy(ori_contact_address);
-               }else break;
-               i++;
-       }while(!found_valid_contact);
-       if (!found_valid_contact)
-               ms_message("Contact do not match, resending register.");
-       else return FALSE;
-
-       eXosip_lock();
-       eXosip_register_build_register(op->rid,op->expires,&msg);
-       if (msg==NULL){
-           eXosip_unlock();
-           ms_warning("Fail to create a contact updated register.");
-           return FALSE;
-       }
-       if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) {
-               eXosip_register_send_register(op->rid,msg);
-               eXosip_unlock();  
-               ms_message("Resending new register with updated contact");
-               update_contact_from_response(op,last_answer);
-               return TRUE;
-       } else {
-           ms_warning("Fail to send updated register.");
-           eXosip_unlock();
-           return FALSE;
-       }
-       eXosip_unlock();
-       return FALSE;
-}
-
-static void registration_success(Sal *sal, eXosip_event_t *ev){
-       SalOp *op=sal_find_register(sal,ev->rid);
-       osip_header_t *h=NULL;
-       bool_t registered;
-       if (op==NULL){
-               ms_error("Receiving register response for unknown operation");
-               return;
-       }
-       osip_message_get_expires(ev->request,0,&h);
-       if (h!=NULL && atoi(h->hvalue)!=0){
-               registered=TRUE;
-               if (!register_again_with_updated_contact(op,ev->request,ev->response)){
-                       sal->callbacks.register_success(op,registered);
-               }
-       }else {
-               sal->callbacks.register_success(op,FALSE);
-       }
-}
-
-static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){
-       int status_code=0;
-       const char *reason=NULL;
-       SalOp *op=sal_find_register(sal,ev->rid);
-       SalReason sr=SalReasonUnknown;
-       SalError se=SalErrorUnknown;
-       
-       if (op==NULL){
-               ms_error("Receiving register failure for unknown operation");
-               return TRUE;
-       }
-       if (ev->response){
-               status_code=osip_message_get_status_code(ev->response);
-               reason=osip_message_get_reason_phrase(ev->response);
-       }
-       switch(status_code){
-               case 401:
-               case 407:
-                       return process_authentication(sal,ev);
-                       break;
-               case 423: /*interval too brief*/
-                       {/*retry with greater interval */
-                               osip_header_t *h=NULL;
-                               osip_message_t *msg=NULL;
-                               osip_message_header_get_byname(ev->response,"min-expires",0,&h);
-                               if (h && h->hvalue && h->hvalue[0]!='\0'){
-                                       int val=atoi(h->hvalue);
-                                       if (val>op->expires)
-                                               op->expires=val;
-                               }else op->expires*=2;
-                               eXosip_lock();
-                               eXosip_register_build_register(op->rid,op->expires,&msg);
-                               eXosip_register_send_register(op->rid,msg);
-                               eXosip_unlock();
-                       }
-               break;
-               case 606: /*Not acceptable, workaround for proxies that don't like private addresses
-                                in vias, such as ekiga.net 
-                                On the opposite, freephonie.net bugs when via are masqueraded.
-                                */
-                       op->masquerade_via=TRUE;
-               default:
-                       /* if contact is up to date, process the failure, otherwise resend a new register with
-                               updated contact first, just in case the faillure is due to incorrect contact */
-                       if (ev->response && register_again_with_updated_contact(op,ev->request,ev->response))
-                               return TRUE; /*we are retrying with an updated contact*/
-                       if (status_code==403){
-                               se=SalErrorFailure;
-                               sr=SalReasonForbidden;
-                       }else if (status_code==0){
-                               se=SalErrorNoResponse;
-                       }
-                       sal->callbacks.register_failure(op,se,sr,reason);
-       }
-       return TRUE;
-}
-
-static void other_request_reply(Sal *sal,eXosip_event_t *ev){
-       SalOp *op=find_op(sal,ev);
-       if (op==NULL){
-               ms_warning("other_request_reply(): Receiving response to unknown request.");
-               return;
-       }
-       if (ev->response){
-               ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request));
-               update_contact_from_response(op,ev->response);
-               if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0)
-                       sal->callbacks.ping_reply(op);
-       }
-       if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) {
-               /*out of call message acknolegment*/
-               SalTextDeliveryStatus status=SalTextDeliveryFailed;
-               if (ev->response){
-                       if (ev->response->status_code<200){
-                               status=SalTextDeliveryInProgress;
-                       }else if (ev->response->status_code<300 && ev->response->status_code>=200){
-                               status=SalTextDeliveryDone;
-                       }
-               }
-               sal->callbacks.text_delivery_update(op,status);
-       }
-}
-
-static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){
-       SalOp *op=find_op(sal,ev);
-       if (ev->response){
-               if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){
-                       if (op->sipfrag_pending){
-                               send_notify_for_refer(op->did,op->sipfrag_pending);
-                               op->sipfrag_pending=NULL;
-                       }
-               }
-       }
-}
-
-static bool_t process_event(Sal *sal, eXosip_event_t *ev){
-       ms_message("linphone process event get a message %d\n",ev->type);
-       switch(ev->type){
-               case EXOSIP_CALL_ANSWERED:
-                       ms_message("CALL_ANSWERED\n");
-                       call_accepted(sal,ev);
-                       authentication_ok(sal,ev);
-                       break;
-               case EXOSIP_CALL_CLOSED:
-               case EXOSIP_CALL_CANCELLED:
-                       ms_message("CALL_CLOSED or CANCELLED\n");
-                       call_terminated(sal,ev);
-                       break;
-               case EXOSIP_CALL_TIMEOUT:
-               case EXOSIP_CALL_NOANSWER:
-                       ms_message("CALL_TIMEOUT or NOANSWER\n");
-                       return call_failure(sal,ev);
-                       break;
-               case EXOSIP_CALL_REQUESTFAILURE:
-               case EXOSIP_CALL_GLOBALFAILURE:
-               case EXOSIP_CALL_SERVERFAILURE:
-                       ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n");
-                       return call_failure(sal,ev);
-                       break;
-               case EXOSIP_CALL_RELEASED:
-                       ms_message("CALL_RELEASED\n");
-                       call_released(sal, ev);
-                       break;
-               case EXOSIP_CALL_INVITE:
-                       ms_message("CALL_NEW\n");
-                       inc_new_call(sal,ev);
-                       break;
-               case EXOSIP_CALL_REINVITE:
-                       handle_reinvite(sal,ev);
-                       break;
-               case EXOSIP_CALL_ACK:
-                       ms_message("CALL_ACK");
-                       handle_ack(sal,ev);
-                       break;
-               case EXOSIP_CALL_REDIRECTED:
-                       ms_message("CALL_REDIRECTED");
-                       eXosip_default_action(ev);
-                       break;
-               case EXOSIP_CALL_PROCEEDING:
-                       ms_message("CALL_PROCEEDING");
-                       call_proceeding(sal,ev);
-                       break;
-               case EXOSIP_CALL_RINGING:
-                       ms_message("CALL_RINGING");
-                       call_ringing(sal,ev);
-                       authentication_ok(sal,ev);
-                       break;
-               case EXOSIP_CALL_MESSAGE_NEW:
-                       ms_message("EXOSIP_CALL_MESSAGE_NEW");
-                       call_message_new(sal,ev);
-                       break;
-               case EXOSIP_CALL_MESSAGE_REQUESTFAILURE:
-                       if (ev->response &&
-                               (ev->response->status_code==407 || ev->response->status_code==401)){
-                                return process_authentication(sal,ev);
-                       }
-                       break;
-               case EXOSIP_CALL_MESSAGE_ANSWERED:
-                       ms_message("EXOSIP_CALL_MESSAGE_ANSWERED ");
-                       process_in_call_reply(sal,ev);
-               break;
-               case EXOSIP_IN_SUBSCRIPTION_NEW:
-                       ms_message("CALL_IN_SUBSCRIPTION_NEW ");
-                       sal_exosip_subscription_recv(sal,ev);
-                       break;
-               case EXOSIP_IN_SUBSCRIPTION_RELEASED:
-                       ms_message("CALL_SUBSCRIPTION_NEW ");
-                       sal_exosip_in_subscription_closed(sal,ev);
-                       break;
-               case EXOSIP_SUBSCRIPTION_UPDATE:
-                       ms_message("CALL_SUBSCRIPTION_UPDATE");
-                       break;
-               case EXOSIP_SUBSCRIPTION_NOTIFY:
-                       ms_message("CALL_SUBSCRIPTION_NOTIFY");
-                       sal_exosip_notify_recv(sal,ev);
-                       break;
-               case EXOSIP_SUBSCRIPTION_ANSWERED:
-                       ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did);
-                       sal_exosip_subscription_answered(sal,ev);
-                       break;
-               case EXOSIP_SUBSCRIPTION_CLOSED:
-                       ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n");
-                       sal_exosip_subscription_closed(sal,ev);
-                       break;
-               case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:   /**< announce a request failure      */
-                       if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){
-                               return process_authentication(sal,ev);
-                       }
-               case EXOSIP_SUBSCRIPTION_SERVERFAILURE:
-               case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:
-                       sal_exosip_subscription_closed(sal,ev);
-                       break;
-               case EXOSIP_REGISTRATION_FAILURE:
-                       ms_message("REGISTRATION_FAILURE\n");
-                       return registration_failure(sal,ev);
-                       break;
-               case EXOSIP_REGISTRATION_SUCCESS:
-                       authentication_ok(sal,ev);
-                       registration_success(sal,ev);
-                       break;
-               case EXOSIP_MESSAGE_NEW:
-                       other_request(sal,ev);
-                       break;
-               case EXOSIP_MESSAGE_PROCEEDING:
-               case EXOSIP_MESSAGE_ANSWERED:
-               case EXOSIP_MESSAGE_REDIRECTED:
-               case EXOSIP_MESSAGE_SERVERFAILURE:
-               case EXOSIP_MESSAGE_GLOBALFAILURE:
-                       other_request_reply(sal,ev);
-                       break;
-               case EXOSIP_MESSAGE_REQUESTFAILURE:
-               case EXOSIP_NOTIFICATION_REQUESTFAILURE:
-                       if (ev->response) {
-                               switch (ev->response->status_code) {
-                                       case 407:
-                                       case 401:
-                                               return process_authentication(sal,ev);
-                                       case 412: {
-                                               eXosip_automatic_action ();
-                                               return 1;
-                                       }
-                               }
-                       }
-                       other_request_reply(sal,ev);
-                       break;
-               default:
-                       ms_message("Unhandled exosip event ! %i",ev->type);
-                       break;
-       }
-       return TRUE;
-}
-
-int sal_iterate(Sal *sal){
-       eXosip_event_t *ev;
-       while((ev=eXosip_event_wait(0,0))!=NULL){
-               if (process_event(sal,ev))
-                       eXosip_event_free(ev);
-       }
-#ifdef HAVE_EXOSIP_TRYLOCK
-       if (eXosip_trylock()==0){
-               eXosip_automatic_refresh();
-               eXosip_unlock();
-       }else{
-               ms_warning("eXosip_trylock busy.");
-       }
-#else
-       eXosip_lock();
-       eXosip_automatic_refresh();
-       eXosip_unlock();
-#endif
-       return 0;
-}
-
-static void register_set_contact(osip_message_t *msg, const char *contact){
-       osip_uri_param_t *param = NULL;
-       osip_contact_t *ct=NULL;
-       char *line=NULL;
-       /*we get the line parameter choosed by exosip, and add it to our own contact*/
-       osip_message_get_contact(msg,0,&ct);
-       if (ct!=NULL){
-               osip_uri_uparam_get_byname(ct->url, "line", &param);
-               if (param && param->gvalue)
-                       line=osip_strdup(param->gvalue);
-       }
-       _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
-       osip_message_set_contact(msg,contact);
-       osip_message_get_contact(msg,0,&ct);
-       osip_uri_uparam_add(ct->url,osip_strdup("line"),line);
-}
-
-static void sal_register_add_route(osip_message_t *msg, const char *proxy){
-       osip_route_t *route;
-
-       osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free);
-       
-       osip_route_init(&route);
-       if (osip_route_parse(route,proxy)==0){
-               osip_uri_param_t *lr_param = NULL;
-               osip_uri_uparam_get_byname(route->url, "lr", &lr_param);
-               if (lr_param == NULL){
-                       osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL);
-               }
-               osip_list_add(&msg->routes,route,0);
-               return;
-       }
-       osip_route_free(route);
-}
-
-
-int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
-       osip_message_t *msg;
-       const char *contact=sal_op_get_contact(h);
-
-       sal_op_set_route(h,proxy);
-       if (h->rid==-1){
-               SalAddress *from_parsed=sal_address_new(from);
-               char domain[256];
-               char *uri, *domain_ptr = NULL;
-               if (from_parsed==NULL) {
-                       ms_warning("sal_register() bad from %s",from);
-                       return -1;
-               }
-               /* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of
-                  using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */
-               uri = sal_address_as_string_uri_only(from_parsed);
-               if (uri) domain_ptr = strchr(uri, '@');
-               if (domain_ptr) {
-                       snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1);
-               } else {
-                       snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed));
-               }
-               if (uri) ms_free(uri);
-               sal_address_destroy(from_parsed);
-               eXosip_lock();
-               h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg);
-               if (msg){
-                       if (contact) register_set_contact(msg,contact);
-                       sal_register_add_route(msg,proxy);
-                       sal_add_register(h->base.root,h);
-               }else{
-                       ms_error("Could not build initial register.");
-                       eXosip_unlock();
-                       return -1;
-               }
-       }else{
-               eXosip_lock();
-               eXosip_register_build_register(h->rid,expires,&msg);
-               sal_register_add_route(msg,proxy);
-       }
-       if (msg){
-               eXosip_register_send_register(h->rid,msg);
-       }
-       eXosip_unlock();
-       h->expires=expires;
-       return (msg != NULL) ? 0 : -1;
-}
-
-int sal_register_refresh(SalOp *op, int expires){
-       osip_message_t *msg=NULL;
-       const char *contact=sal_op_get_contact(op);
-       
-       if (op->rid==-1){
-               ms_error("Unexistant registration context, not possible to refresh.");
-               return -1;
-       }
-#ifdef HAVE_EXOSIP_TRYLOCK
-       {
-               int tries=0;
-               /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever.
-               * In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take
-               * the exosip lock in a non blocking way, and give up if it takes too long*/
-               while (eXosip_trylock()!=0){
-                       ms_usleep(100000);
-                       if (tries>30) {/*after 3 seconds, give up*/
-                               ms_warning("Could not obtain exosip lock in a reasonable time, giving up.");
-                               return -1;
-                       }
-               }
-       }
-#else
-       eXosip_lock();
-#endif
-       eXosip_register_build_register(op->rid,expires,&msg);
-       if (msg!=NULL){
-               if (contact) register_set_contact(msg,contact);
-               sal_register_add_route(msg,sal_op_get_route(op));
-               eXosip_register_send_register(op->rid,msg);
-       }else ms_error("Could not build REGISTER refresh message.");
-       eXosip_unlock();
-       return (msg != NULL) ? 0 : -1;
-}
-
-
-int sal_unregister(SalOp *h){
-       osip_message_t *msg=NULL;
-       eXosip_lock();
-       eXosip_register_build_register(h->rid,0,&msg);
-       if (msg) eXosip_register_send_register(h->rid,msg);
-       else ms_warning("Could not build unREGISTER !");
-       eXosip_unlock();
-       return 0;
-}
-
-SalAddress * sal_address_new(const char *uri){
-       osip_from_t *from;
-       osip_from_init(&from);
-
-       // Remove front spaces
-       while (uri[0]==' ') {
-               uri++;
-       }
-               
-       if (osip_from_parse(from,uri)!=0){
-               osip_from_free(from);
-               return NULL;
-       }
-       if (from->displayname!=NULL && from->displayname[0]=='"'){
-               char *unquoted=osip_strdup_without_quote(from->displayname);
-               osip_free(from->displayname);
-               from->displayname=unquoted;
-       }
-       return (SalAddress*)from;
-}
-
-SalAddress * sal_address_clone(const SalAddress *addr){
-       osip_from_t *ret=NULL;
-       osip_from_clone((osip_from_t*)addr,&ret);
-       return (SalAddress*)ret;
-}
-
-#define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL )
-
-const char *sal_address_get_scheme(const SalAddress *addr){
-       const osip_from_t *u=(const osip_from_t*)addr;
-       return null_if_empty(u->url->scheme);
-}
-
-const char *sal_address_get_display_name(const SalAddress* addr){
-       const osip_from_t *u=(const osip_from_t*)addr;
-       return null_if_empty(u->displayname);
-}
-
-const char *sal_address_get_username(const SalAddress *addr){
-       const osip_from_t *u=(const osip_from_t*)addr;
-       return null_if_empty(u->url->username);
-}
-
-const char *sal_address_get_domain(const SalAddress *addr){
-       const osip_from_t *u=(const osip_from_t*)addr;
-       return null_if_empty(u->url->host);
-}
-
-void sal_address_set_display_name(SalAddress *addr, const char *display_name){
-       osip_from_t *u=(osip_from_t*)addr;
-       if (u->displayname!=NULL){
-               osip_free(u->displayname);
-               u->displayname=NULL;
-       }
-       if (display_name!=NULL && display_name[0]!='\0'){
-               u->displayname=osip_strdup(display_name);
-       }
-}
-
-void sal_address_set_username(SalAddress *addr, const char *username){
-       osip_from_t *uri=(osip_from_t*)addr;
-       if (uri->url->username!=NULL){
-               osip_free(uri->url->username);
-               uri->url->username=NULL;
-       }
-       if (username)
-               uri->url->username=osip_strdup(username);
-}
-
-void sal_address_set_domain(SalAddress *addr, const char *host){
-       osip_from_t *uri=(osip_from_t*)addr;
-       if (uri->url->host!=NULL){
-               osip_free(uri->url->host);
-               uri->url->host=NULL;
-       }
-       if (host)
-               uri->url->host=osip_strdup(host);
-}
-
-void sal_address_set_port(SalAddress *addr, const char *port){
-       osip_from_t *uri=(osip_from_t*)addr;
-       if (uri->url->port!=NULL){
-               osip_free(uri->url->port);
-               uri->url->port=NULL;
-       }
-       if (port)
-               uri->url->port=osip_strdup(port);
-}
-
-void sal_address_set_port_int(SalAddress *uri, int port){
-       char tmp[12];
-       if (port==5060){
-               /*this is the default, special case to leave the port field blank*/
-               sal_address_set_port(uri,NULL);
-               return;
-       }
-       snprintf(tmp,sizeof(tmp),"%i",port);
-       sal_address_set_port(uri,tmp);
-}
-
-void sal_address_clean(SalAddress *addr){
-       osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params);
-       osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params);
-}
-
-char *sal_address_as_string(const SalAddress *u){
-       char *tmp,*ret;
-       osip_from_t *from=(osip_from_t *)u;
-       char *old_displayname=NULL;
-       /* hack to force use of quotes around the displayname*/
-       if (from->displayname!=NULL
-           && from->displayname[0]!='"'){
-               old_displayname=from->displayname;
-               from->displayname=osip_enquote(from->displayname);
-       }
-       osip_from_to_str(from,&tmp);
-       if (old_displayname!=NULL){
-               ms_free(from->displayname);
-               from->displayname=old_displayname;
-       }
-       ret=ms_strdup(tmp);
-       osip_free(tmp);
-       return ret;
-}
-
-char *sal_address_as_string_uri_only(const SalAddress *u){
-       char *tmp=NULL,*ret;
-       osip_uri_to_str(((osip_from_t*)u)->url,&tmp);
-       ret=ms_strdup(tmp);
-       osip_free(tmp);
-       return ret;
-}
-void sal_address_set_param(SalAddress *u,const char* name,const char* value) {
-       osip_uri_param_t *param=NULL;
-    osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,&param);
-    if (param == NULL){
-        osip_uri_uparam_add    (((osip_from_t*)u)->url,ms_strdup(name),value ? ms_strdup(value) : NULL);
-    } else {
-        osip_free(param->gvalue);
-        param->gvalue=value ? osip_strdup(value) : NULL;
-    }
-    
-}
-
-void sal_address_destroy(SalAddress *u){
-       osip_from_free((osip_from_t*)u);
-}
-
-void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) {
-       ctx->tcp_tls_keepalive = enabled;
-}
-
-void sal_set_keepalive_period(Sal *ctx,unsigned int value) {
-       switch (ctx->transport) {
-               case SalTransportUDP:
-                       ctx->keepalive_period = value;
-                       break;
-               case SalTransportTCP:
-               case SalTransportTLS:
-                       if (ctx->tcp_tls_keepalive) ctx->keepalive_period = value;
-                       else ctx->keepalive_period = -1;
-                       break;
-               default:
-                       break;
-       }
-       eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period);
-}
-unsigned int sal_get_keepalive_period(Sal *ctx) {
-       return ctx->keepalive_period;
-}
-
-const char * sal_address_get_port(const SalAddress *addr) {
-       const osip_from_t *u=(const osip_from_t*)addr;
-       return null_if_empty(u->url->port);
-}
-
-int sal_address_get_port_int(const SalAddress *uri) {
-       const char* port = sal_address_get_port(uri);
-       if (port != NULL) {
-               return atoi(port);
-       } else {
-               return 5060;
-       }
-}
-SalTransport sal_address_get_transport(const SalAddress* addr) {
-    const osip_from_t *u=(const osip_from_t*)addr;
-    osip_uri_param_t *transport_param=NULL;
-    osip_uri_uparam_get_byname(u->url,"transport",&transport_param);
-    if (transport_param == NULL){
-        return SalTransportUDP;
-    }  else {
-        return sal_transport_parse(transport_param->gvalue);
-    }
-}
-void sal_address_set_transport(SalAddress* addr,SalTransport transport) {
-    sal_address_set_param(addr, "transport", sal_transport_to_string(transport));
-}
-
-/* sends a reinvite. Local media description may have changed by application since call establishment*/
-int sal_call_update(SalOp *h, const char *subject){
-       int err=0;
-       osip_message_t *reinvite=NULL;
-
-       eXosip_lock();
-       if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){
-               eXosip_unlock();
-               return -1;
-       }
-       eXosip_unlock();
-       osip_message_set_subject(reinvite,subject);
-       osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
-       if (h->base.contact){
-               _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free);
-               osip_message_set_contact(reinvite,h->base.contact);
-       }
-       if (h->base.root->session_expires!=0){
-               osip_message_set_header(reinvite, "Session-expires", "200");
-               osip_message_set_supported(reinvite, "timer");
-       }
-       if (h->base.local_media){
-               h->sdp_offering=TRUE;
-               set_sdp_from_desc(reinvite,h->base.local_media);
-       }else h->sdp_offering=FALSE;
-       eXosip_lock();
-       err = eXosip_call_send_request(h->did, reinvite);
-       eXosip_unlock();
-       return err;
-}
-void sal_reuse_authorization(Sal *ctx, bool_t value) {
-       ctx->reuse_authorization=value;
-}
+static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};\r
+\r
+static void text_received(Sal *sal, eXosip_event_t *ev){\r
+       osip_body_t *body=NULL;\r
+       char *from=NULL,*msg=NULL;\r
+       osip_content_type_t* content_type;\r
+       osip_uri_param_t* external_body_url; \r
+       char unquoted_external_body_url [256];\r
+       int external_body_size=0;\r
+       SalMessage salmsg;\r
+       char message_id[256]={0};\r
+       osip_header_t *date=NULL;\r
+       struct tm ret={0};\r
+       char tmp1[80]={0};\r
+       char tmp2[80]={0};\r
+       SalOp *op=sal_op_new(sal);\r
+\r
+       osip_message_get_date(ev->request,0,&date);\r
+       if(date!=NULL){\r
+               int i,j;\r
+               sscanf(date->hvalue,"%3c,%d%s%d%d:%d:%d",tmp1,&ret.tm_mday,tmp2,\r
+                    &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec);\r
+               ret.tm_year-=1900;\r
+               for(i=0;i<7;i++) { \r
+                       if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; \r
+               }\r
+               for(j=0;j<12;j++) { \r
+                       if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; \r
+               }\r
+       }else ms_warning("No date header in SIP MESSAGE, we don't know when it was sent.");\r
+       \r
+       \r
+       content_type= osip_message_get_content_type(ev->request);\r
+       if (!content_type) {\r
+               ms_error("Could not get message because no content type");\r
+               return;\r
+       }\r
+       osip_from_to_str(ev->request->from,&from);\r
+       if (content_type->type \r
+               && strcmp(content_type->type, "text")==0 \r
+               && content_type->subtype\r
+               && strcmp(content_type->subtype, "plain")==0 ) {\r
+               osip_message_get_body(ev->request,0,&body);\r
+               if (body==NULL){\r
+                       ms_error("Could not get text message from SIP body");\r
+                       osip_free(from);\r
+                       return;\r
+               }\r
+               msg=body->body;\r
+       }else if (content_type->type \r
+                 && strcmp(content_type->type, "message")==0 \r
+                 && content_type->subtype\r
+                 && strcmp(content_type->subtype, "external-body")==0 ) {\r
+               \r
+               osip_content_type_param_get_byname(content_type, "URL", &external_body_url);\r
+               /*remove both first and last character*/\r
+               strncpy(unquoted_external_body_url\r
+                               ,&external_body_url->gvalue[1]\r
+                               ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url)));\r
+               unquoted_external_body_url[external_body_size-1]='\0';\r
+       } else {\r
+               ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype);\r
+               osip_free(from);\r
+               return;\r
+       }\r
+       sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request));\r
+       \r
+       snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number);\r
+       \r
+       salmsg.from=from;\r
+       salmsg.text=msg;\r
+       salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL;\r
+       salmsg.message_id=message_id;\r
+       salmsg.time=date!=NULL ? mktime(&ret) : time(NULL);\r
+       sal->callbacks.text_received(op,&salmsg);\r
+       sal_op_release(op);\r
+       osip_free(from);\r
+}\r
+\r
+\r
+\r
+static void other_request(Sal *sal, eXosip_event_t *ev){\r
+       ms_message("in other_request");\r
+       if (ev->request==NULL) return;\r
+       if (strcmp(ev->request->sip_method,"MESSAGE")==0){\r
+               text_received(sal,ev);\r
+               eXosip_message_send_answer(ev->tid,200,NULL);\r
+       }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){\r
+               osip_message_t *options=NULL;\r
+               eXosip_options_build_answer(ev->tid,200,&options);\r
+               fill_options_answer(options);\r
+               eXosip_options_send_answer(ev->tid,200,options);\r
+       }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){\r
+               ms_message("Receiving REFER request !");\r
+               if (comes_from_local_if(ev->request)) {\r
+                       process_refer(sal,NULL,ev);\r
+               }else ms_warning("Ignored REFER not coming from this local loopback interface.");\r
+       }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){\r
+               inc_update(sal,ev);\r
+       }else {\r
+               char *tmp=NULL;\r
+               size_t msglen=0;\r
+               osip_message_to_str(ev->request,&tmp,&msglen);\r
+               if (tmp){\r
+                       ms_message("Unsupported request received:\n%s",tmp);\r
+                       osip_free(tmp);\r
+               }\r
+               /*answer with a 501 Not implemented*/\r
+               eXosip_message_send_answer(ev->tid,501,NULL);\r
+       }\r
+}\r
+\r
+static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){\r
+       osip_via_t *via=NULL;\r
+       osip_message_get_via(msg,0,&via);\r
+       if (via){\r
+               osip_free(via->port);\r
+               via->port=osip_strdup(port);\r
+               osip_free(via->host);\r
+               via->host=osip_strdup(ip);\r
+       }\r
+}\r
+\r
+\r
+static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) {\r
+       osip_contact_t *ctt=NULL;\r
+       const char *received;\r
+       int rport;\r
+       SalTransport transport;\r
+       char port[20];\r
+\r
+       if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;\r
+       osip_message_get_contact(request,0,&ctt);\r
+       if (ctt == NULL) {\r
+               ms_warning("fix_message_contact(): no contact to update");\r
+               return FALSE;\r
+       }\r
+       if (expire_last_contact){\r
+               osip_contact_t *oldct=NULL,*prevct;\r
+               osip_generic_param_t *param=NULL;\r
+               osip_contact_clone(ctt,&oldct);\r
+               while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){\r
+                       osip_contact_free(prevct);\r
+                       osip_list_remove(&request->contacts,1);\r
+               }\r
+               osip_list_add(&request->contacts,oldct,1);\r
+               osip_contact_param_get_byname(oldct,"expires",&param);\r
+               if (param){\r
+                       if (param->gvalue) osip_free(param->gvalue);\r
+                       param->gvalue=osip_strdup("0");\r
+               }else{\r
+                       osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0"));\r
+               }\r
+       }\r
+       if (ctt->url->host!=NULL){\r
+               osip_free(ctt->url->host);\r
+       }\r
+       ctt->url->host=osip_strdup(received);\r
+       if (ctt->url->port!=NULL){\r
+               osip_free(ctt->url->port);\r
+       }\r
+       snprintf(port,sizeof(port),"%i",rport);\r
+       ctt->url->port=osip_strdup(port);\r
+       if (op->masquerade_via) masquerade_via(request,received,port);\r
+\r
+       if (transport != SalTransportUDP) {\r
+               sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport)); \r
+       }\r
+       return TRUE;    \r
+}\r
+\r
+static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){\r
+       osip_contact_t *ctt=NULL;\r
+       SalAddress* ori_contact_address=NULL;\r
+       const char *received;\r
+       int rport;\r
+       SalTransport transport;\r
+       char* tmp;\r
+       osip_message_t *msg=NULL;\r
+       Sal* sal=op->base.root;\r
+       int i=0;\r
+       bool_t found_valid_contact=FALSE;\r
+       bool_t from_request=FALSE;\r
+\r
+       if (sal->double_reg==FALSE ) return FALSE; \r
+\r
+       if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE;\r
+       do{\r
+               ctt=NULL;\r
+               osip_message_get_contact(last_answer,i,&ctt);\r
+               if (!from_request && ctt==NULL) {\r
+                       osip_message_get_contact(orig_request,0,&ctt);\r
+                       from_request=TRUE;\r
+               }\r
+               if (ctt){\r
+                       osip_contact_to_str(ctt,&tmp);\r
+                       ori_contact_address = sal_address_new(tmp);\r
+       \r
+                       /*check if contact is up to date*/\r
+                       if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0 \r
+                               && sal_address_get_port_int(ori_contact_address) == rport\r
+                       && sal_address_get_transport(ori_contact_address) == transport) {\r
+                               if (!from_request){\r
+                                       ms_message("Register response has up to date contact, doing nothing.");\r
+                               }else {\r
+                                       ms_warning("Register response does not have up to date contact, but last request had."\r
+                                               "Stupid registrar detected, giving up.");\r
+                               }\r
+                               found_valid_contact=TRUE;\r
+                       }\r
+                       osip_free(tmp);\r
+                       sal_address_destroy(ori_contact_address);\r
+               }else break;\r
+               i++;\r
+       }while(!found_valid_contact);\r
+       if (!found_valid_contact)\r
+               ms_message("Contact do not match, resending register.");\r
+       else return FALSE;\r
+\r
+       eXosip_lock();\r
+       eXosip_register_build_register(op->rid,op->expires,&msg);\r
+       if (msg==NULL){\r
+           eXosip_unlock();\r
+           ms_warning("Fail to create a contact updated register.");\r
+           return FALSE;\r
+       }\r
+       if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) {\r
+               eXosip_register_send_register(op->rid,msg);\r
+               eXosip_unlock();  \r
+               ms_message("Resending new register with updated contact");\r
+               update_contact_from_response(op,last_answer);\r
+               return TRUE;\r
+       } else {\r
+           ms_warning("Fail to send updated register.");\r
+           eXosip_unlock();\r
+           return FALSE;\r
+       }\r
+       eXosip_unlock();\r
+       return FALSE;\r
+}\r
+\r
+static void registration_success(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op=sal_find_register(sal,ev->rid);\r
+       osip_header_t *h=NULL;\r
+       bool_t registered;\r
+       if (op==NULL){\r
+               ms_error("Receiving register response for unknown operation");\r
+               return;\r
+       }\r
+       osip_message_get_expires(ev->request,0,&h);\r
+       if (h!=NULL && atoi(h->hvalue)!=0){\r
+               registered=TRUE;\r
+               if (!register_again_with_updated_contact(op,ev->request,ev->response)){\r
+                       sal->callbacks.register_success(op,registered);\r
+               }\r
+       }else {\r
+               sal->callbacks.register_success(op,FALSE);\r
+       }\r
+}\r
+\r
+static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){\r
+       int status_code=0;\r
+       const char *reason=NULL;\r
+       SalOp *op=sal_find_register(sal,ev->rid);\r
+       SalReason sr=SalReasonUnknown;\r
+       SalError se=SalErrorUnknown;\r
+       \r
+       if (op==NULL){\r
+               ms_error("Receiving register failure for unknown operation");\r
+               return TRUE;\r
+       }\r
+       if (ev->response){\r
+               status_code=osip_message_get_status_code(ev->response);\r
+               reason=osip_message_get_reason_phrase(ev->response);\r
+       }\r
+       switch(status_code){\r
+               case 401:\r
+               case 407:\r
+                       return process_authentication(sal,ev);\r
+                       break;\r
+               case 423: /*interval too brief*/\r
+                       {/*retry with greater interval */\r
+                               osip_header_t *h=NULL;\r
+                               osip_message_t *msg=NULL;\r
+                               osip_message_header_get_byname(ev->response,"min-expires",0,&h);\r
+                               if (h && h->hvalue && h->hvalue[0]!='\0'){\r
+                                       int val=atoi(h->hvalue);\r
+                                       if (val>op->expires)\r
+                                               op->expires=val;\r
+                               }else op->expires*=2;\r
+                               eXosip_lock();\r
+                               eXosip_register_build_register(op->rid,op->expires,&msg);\r
+                               eXosip_register_send_register(op->rid,msg);\r
+                               eXosip_unlock();\r
+                       }\r
+               break;\r
+               case 606: /*Not acceptable, workaround for proxies that don't like private addresses\r
+                                in vias, such as ekiga.net \r
+                                On the opposite, freephonie.net bugs when via are masqueraded.\r
+                                */\r
+                       op->masquerade_via=TRUE;\r
+               default:\r
+                       /* if contact is up to date, process the failure, otherwise resend a new register with\r
+                               updated contact first, just in case the faillure is due to incorrect contact */\r
+                       if (ev->response && register_again_with_updated_contact(op,ev->request,ev->response))\r
+                               return TRUE; /*we are retrying with an updated contact*/\r
+                       if (status_code==403){\r
+                               se=SalErrorFailure;\r
+                               sr=SalReasonForbidden;\r
+                       }else if (status_code==0){\r
+                               se=SalErrorNoResponse;\r
+                       }\r
+                       sal->callbacks.register_failure(op,se,sr,reason);\r
+       }\r
+       return TRUE;\r
+}\r
+\r
+static void other_request_reply(Sal *sal,eXosip_event_t *ev){\r
+       SalOp *op=find_op(sal,ev);\r
+       if (op==NULL){\r
+               ms_warning("other_request_reply(): Receiving response to unknown request.");\r
+               return;\r
+       }\r
+       if (ev->response){\r
+               ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request));\r
+               update_contact_from_response(op,ev->response);\r
+               if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0)\r
+                       sal->callbacks.ping_reply(op);\r
+       }\r
+       if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) {\r
+               /*out of call message acknolegment*/\r
+               SalTextDeliveryStatus status=SalTextDeliveryFailed;\r
+               if (ev->response){\r
+                       if (ev->response->status_code<200){\r
+                               status=SalTextDeliveryInProgress;\r
+                       }else if (ev->response->status_code<300 && ev->response->status_code>=200){\r
+                               status=SalTextDeliveryDone;\r
+                       }\r
+               }\r
+               sal->callbacks.text_delivery_update(op,status);\r
+       }\r
+}\r
+\r
+static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){\r
+       SalOp *op=find_op(sal,ev);\r
+       if (ev->response){\r
+               if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){\r
+                       if (op->sipfrag_pending){\r
+                               send_notify_for_refer(op->did,op->sipfrag_pending);\r
+                               op->sipfrag_pending=NULL;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+static bool_t process_event(Sal *sal, eXosip_event_t *ev){\r
+       ms_message("linphone process event get a message %d\n",ev->type);\r
+       switch(ev->type){\r
+               case EXOSIP_CALL_ANSWERED:\r
+                       ms_message("CALL_ANSWERED\n");\r
+                       call_accepted(sal,ev);\r
+                       authentication_ok(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_CLOSED:\r
+               case EXOSIP_CALL_CANCELLED:\r
+                       ms_message("CALL_CLOSED or CANCELLED\n");\r
+                       call_terminated(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_TIMEOUT:\r
+               case EXOSIP_CALL_NOANSWER:\r
+                       ms_message("CALL_TIMEOUT or NOANSWER\n");\r
+                       return call_failure(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_REQUESTFAILURE:\r
+               case EXOSIP_CALL_GLOBALFAILURE:\r
+               case EXOSIP_CALL_SERVERFAILURE:\r
+                       ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n");\r
+                       return call_failure(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_RELEASED:\r
+                       ms_message("CALL_RELEASED\n");\r
+                       call_released(sal, ev);\r
+                       break;\r
+               case EXOSIP_CALL_INVITE:\r
+                       ms_message("CALL_NEW\n");\r
+                       inc_new_call(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_REINVITE:\r
+                       handle_reinvite(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_ACK:\r
+                       ms_message("CALL_ACK");\r
+                       handle_ack(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_REDIRECTED:\r
+                       ms_message("CALL_REDIRECTED");\r
+                       eXosip_default_action(ev);\r
+                       break;\r
+               case EXOSIP_CALL_PROCEEDING:\r
+                       ms_message("CALL_PROCEEDING");\r
+                       call_proceeding(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_RINGING:\r
+                       ms_message("CALL_RINGING");\r
+                       call_ringing(sal,ev);\r
+                       authentication_ok(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_MESSAGE_NEW:\r
+                       ms_message("EXOSIP_CALL_MESSAGE_NEW");\r
+                       call_message_new(sal,ev);\r
+                       break;\r
+               case EXOSIP_CALL_MESSAGE_REQUESTFAILURE:\r
+                       if (ev->response &&\r
+                               (ev->response->status_code==407 || ev->response->status_code==401)){\r
+                                return process_authentication(sal,ev);\r
+                       }\r
+                       break;\r
+               case EXOSIP_CALL_MESSAGE_ANSWERED:\r
+                       ms_message("EXOSIP_CALL_MESSAGE_ANSWERED ");\r
+                       process_in_call_reply(sal,ev);\r
+               break;\r
+               case EXOSIP_IN_SUBSCRIPTION_NEW:\r
+                       ms_message("CALL_IN_SUBSCRIPTION_NEW ");\r
+                       sal_exosip_subscription_recv(sal,ev);\r
+                       break;\r
+               case EXOSIP_IN_SUBSCRIPTION_RELEASED:\r
+                       ms_message("CALL_SUBSCRIPTION_NEW ");\r
+                       sal_exosip_in_subscription_closed(sal,ev);\r
+                       break;\r
+               case EXOSIP_SUBSCRIPTION_UPDATE:\r
+                       ms_message("CALL_SUBSCRIPTION_UPDATE");\r
+                       break;\r
+               case EXOSIP_SUBSCRIPTION_NOTIFY:\r
+                       ms_message("CALL_SUBSCRIPTION_NOTIFY");\r
+                       sal_exosip_notify_recv(sal,ev);\r
+                       break;\r
+               case EXOSIP_SUBSCRIPTION_ANSWERED:\r
+                       ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did);\r
+                       sal_exosip_subscription_answered(sal,ev);\r
+                       break;\r
+               case EXOSIP_SUBSCRIPTION_CLOSED:\r
+                       ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n");\r
+                       sal_exosip_subscription_closed(sal,ev);\r
+                       break;\r
+               case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:   /**< announce a request failure      */\r
+                       if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){\r
+                               return process_authentication(sal,ev);\r
+                       }\r
+               case EXOSIP_SUBSCRIPTION_SERVERFAILURE:\r
+               case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:\r
+                       sal_exosip_subscription_closed(sal,ev);\r
+                       break;\r
+               case EXOSIP_REGISTRATION_FAILURE:\r
+                       ms_message("REGISTRATION_FAILURE\n");\r
+                       return registration_failure(sal,ev);\r
+                       break;\r
+               case EXOSIP_REGISTRATION_SUCCESS:\r
+                       authentication_ok(sal,ev);\r
+                       registration_success(sal,ev);\r
+                       break;\r
+               case EXOSIP_MESSAGE_NEW:\r
+                       other_request(sal,ev);\r
+                       break;\r
+               case EXOSIP_MESSAGE_PROCEEDING:\r
+               case EXOSIP_MESSAGE_ANSWERED:\r
+               case EXOSIP_MESSAGE_REDIRECTED:\r
+               case EXOSIP_MESSAGE_SERVERFAILURE:\r
+               case EXOSIP_MESSAGE_GLOBALFAILURE:\r
+                       other_request_reply(sal,ev);\r
+                       break;\r
+               case EXOSIP_MESSAGE_REQUESTFAILURE:\r
+               case EXOSIP_NOTIFICATION_REQUESTFAILURE:\r
+                       if (ev->response) {\r
+                               switch (ev->response->status_code) {\r
+                                       case 407:\r
+                                       case 401:\r
+                                               return process_authentication(sal,ev);\r
+                                       case 412: {\r
+                                               eXosip_automatic_action ();\r
+                                               return 1;\r
+                                       }\r
+                               }\r
+                       }\r
+                       other_request_reply(sal,ev);\r
+                       break;\r
+               default:\r
+                       ms_message("Unhandled exosip event ! %i",ev->type);\r
+                       break;\r
+       }\r
+       return TRUE;\r
+}\r
+\r
+int sal_iterate(Sal *sal){\r
+       eXosip_event_t *ev;\r
+       while((ev=eXosip_event_wait(0,0))!=NULL){\r
+               if (process_event(sal,ev))\r
+                       eXosip_event_free(ev);\r
+       }\r
+#ifdef HAVE_EXOSIP_TRYLOCK\r
+       if (eXosip_trylock()==0){\r
+               eXosip_automatic_refresh();\r
+               eXosip_unlock();\r
+       }else{\r
+               ms_warning("eXosip_trylock busy.");\r
+       }\r
+#else\r
+       eXosip_lock();\r
+       eXosip_automatic_refresh();\r
+       eXosip_unlock();\r
+#endif\r
+       return 0;\r
+}\r
+\r
+static void register_set_contact(osip_message_t *msg, const char *contact){\r
+       osip_uri_param_t *param = NULL;\r
+       osip_contact_t *ct=NULL;\r
+       char *line=NULL;\r
+       /*we get the line parameter choosed by exosip, and add it to our own contact*/\r
+       osip_message_get_contact(msg,0,&ct);\r
+       if (ct!=NULL){\r
+               osip_uri_uparam_get_byname(ct->url, "line", &param);\r
+               if (param && param->gvalue)\r
+                       line=osip_strdup(param->gvalue);\r
+       }\r
+       _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);\r
+       osip_message_set_contact(msg,contact);\r
+       osip_message_get_contact(msg,0,&ct);\r
+       osip_uri_uparam_add(ct->url,osip_strdup("line"),line);\r
+}\r
+\r
+static void sal_register_add_route(osip_message_t *msg, const char *proxy){\r
+       osip_route_t *route;\r
+\r
+       osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free);\r
+       \r
+       osip_route_init(&route);\r
+       if (osip_route_parse(route,proxy)==0){\r
+               osip_uri_param_t *lr_param = NULL;\r
+               osip_uri_uparam_get_byname(route->url, "lr", &lr_param);\r
+               if (lr_param == NULL){\r
+                       osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL);\r
+               }\r
+               osip_list_add(&msg->routes,route,0);\r
+               return;\r
+       }\r
+       osip_route_free(route);\r
+}\r
+\r
+\r
+int sal_register(SalOp *h, const char *proxy, const char *from, int expires){\r
+       osip_message_t *msg;\r
+       const char *contact=sal_op_get_contact(h);\r
+\r
+       sal_op_set_route(h,proxy);\r
+       if (h->rid==-1){\r
+               SalAddress *from_parsed=sal_address_new(from);\r
+               char domain[256];\r
+               char *uri, *domain_ptr = NULL;\r
+               if (from_parsed==NULL) {\r
+                       ms_warning("sal_register() bad from %s",from);\r
+                       return -1;\r
+               }\r
+               /* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of\r
+                  using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */\r
+               uri = sal_address_as_string_uri_only(from_parsed);\r
+               if (uri) domain_ptr = strchr(uri, '@');\r
+               if (domain_ptr) {\r
+                       snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1);\r
+               } else {\r
+                       snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed));\r
+               }\r
+               if (uri) ms_free(uri);\r
+               sal_address_destroy(from_parsed);\r
+               eXosip_lock();\r
+               h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg);\r
+               if (msg){\r
+                       if (contact) register_set_contact(msg,contact);\r
+                       sal_register_add_route(msg,proxy);\r
+                       sal_add_register(h->base.root,h);\r
+               }else{\r
+                       ms_error("Could not build initial register.");\r
+                       eXosip_unlock();\r
+                       return -1;\r
+               }\r
+       }else{\r
+               eXosip_lock();\r
+               eXosip_register_build_register(h->rid,expires,&msg);\r
+               sal_register_add_route(msg,proxy);\r
+       }\r
+       if (msg){\r
+               eXosip_register_send_register(h->rid,msg);\r
+       }\r
+       eXosip_unlock();\r
+       h->expires=expires;\r
+       return (msg != NULL) ? 0 : -1;\r
+}\r
+\r
+int sal_register_refresh(SalOp *op, int expires){\r
+       osip_message_t *msg=NULL;\r
+       const char *contact=sal_op_get_contact(op);\r
+       \r
+       if (op->rid==-1){\r
+               ms_error("Unexistant registration context, not possible to refresh.");\r
+               return -1;\r
+       }\r
+#ifdef HAVE_EXOSIP_TRYLOCK\r
+       {\r
+               int tries=0;\r
+               /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever.\r
+               * In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take\r
+               * the exosip lock in a non blocking way, and give up if it takes too long*/\r
+               while (eXosip_trylock()!=0){\r
+                       ms_usleep(100000);\r
+                       if (tries>30) {/*after 3 seconds, give up*/\r
+                               ms_warning("Could not obtain exosip lock in a reasonable time, giving up.");\r
+                               return -1;\r
+                       }\r
+               }\r
+       }\r
+#else\r
+       eXosip_lock();\r
+#endif\r
+       eXosip_register_build_register(op->rid,expires,&msg);\r
+       if (msg!=NULL){\r
+               if (contact) register_set_contact(msg,contact);\r
+               sal_register_add_route(msg,sal_op_get_route(op));\r
+               eXosip_register_send_register(op->rid,msg);\r
+       }else ms_error("Could not build REGISTER refresh message.");\r
+       eXosip_unlock();\r
+       return (msg != NULL) ? 0 : -1;\r
+}\r
+\r
+\r
+int sal_unregister(SalOp *h){\r
+       osip_message_t *msg=NULL;\r
+       eXosip_lock();\r
+       eXosip_register_build_register(h->rid,0,&msg);\r
+       if (msg) eXosip_register_send_register(h->rid,msg);\r
+       else ms_warning("Could not build unREGISTER !");\r
+       eXosip_unlock();\r
+       return 0;\r
+}\r
+\r
+SalAddress * sal_address_new(const char *uri){\r
+       osip_from_t *from;\r
+       osip_from_init(&from);\r
+\r
+       // Remove front spaces\r
+       while (uri[0]==' ') {\r
+               uri++;\r
+       }\r
+               \r
+       if (osip_from_parse(from,uri)!=0){\r
+               osip_from_free(from);\r
+               return NULL;\r
+       }\r
+       if (from->displayname!=NULL && from->displayname[0]=='"'){\r
+               char *unquoted=osip_strdup_without_quote(from->displayname);\r
+               osip_free(from->displayname);\r
+               from->displayname=unquoted;\r
+       }\r
+       return (SalAddress*)from;\r
+}\r
+\r
+SalAddress * sal_address_clone(const SalAddress *addr){\r
+       osip_from_t *ret=NULL;\r
+       osip_from_clone((osip_from_t*)addr,&ret);\r
+       return (SalAddress*)ret;\r
+}\r
+\r
+#define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL )\r
+\r
+const char *sal_address_get_scheme(const SalAddress *addr){\r
+       const osip_from_t *u=(const osip_from_t*)addr;\r
+       return null_if_empty(u->url->scheme);\r
+}\r
+\r
+const char *sal_address_get_display_name(const SalAddress* addr){\r
+       const osip_from_t *u=(const osip_from_t*)addr;\r
+       return null_if_empty(u->displayname);\r
+}\r
+\r
+const char *sal_address_get_username(const SalAddress *addr){\r
+       const osip_from_t *u=(const osip_from_t*)addr;\r
+       return null_if_empty(u->url->username);\r
+}\r
+\r
+const char *sal_address_get_domain(const SalAddress *addr){\r
+       const osip_from_t *u=(const osip_from_t*)addr;\r
+       return null_if_empty(u->url->host);\r
+}\r
+\r
+void sal_address_set_display_name(SalAddress *addr, const char *display_name){\r
+       osip_from_t *u=(osip_from_t*)addr;\r
+       if (u->displayname!=NULL){\r
+               osip_free(u->displayname);\r
+               u->displayname=NULL;\r
+       }\r
+       if (display_name!=NULL && display_name[0]!='\0'){\r
+               u->displayname=osip_strdup(display_name);\r
+       }\r
+}\r
+\r
+void sal_address_set_username(SalAddress *addr, const char *username){\r
+       osip_from_t *uri=(osip_from_t*)addr;\r
+       if (uri->url->username!=NULL){\r
+               osip_free(uri->url->username);\r
+               uri->url->username=NULL;\r
+       }\r
+       if (username)\r
+               uri->url->username=osip_strdup(username);\r
+}\r
+\r
+void sal_address_set_domain(SalAddress *addr, const char *host){\r
+       osip_from_t *uri=(osip_from_t*)addr;\r
+       if (uri->url->host!=NULL){\r
+               osip_free(uri->url->host);\r
+               uri->url->host=NULL;\r
+       }\r
+       if (host)\r
+               uri->url->host=osip_strdup(host);\r
+}\r
+\r
+void sal_address_set_port(SalAddress *addr, const char *port){\r
+       osip_from_t *uri=(osip_from_t*)addr;\r
+       if (uri->url->port!=NULL){\r
+               osip_free(uri->url->port);\r
+               uri->url->port=NULL;\r
+       }\r
+       if (port)\r
+               uri->url->port=osip_strdup(port);\r
+}\r
+\r
+void sal_address_set_port_int(SalAddress *uri, int port){\r
+       char tmp[12];\r
+       if (port==5060){\r
+               /*this is the default, special case to leave the port field blank*/\r
+               sal_address_set_port(uri,NULL);\r
+               return;\r
+       }\r
+       snprintf(tmp,sizeof(tmp),"%i",port);\r
+       sal_address_set_port(uri,tmp);\r
+}\r
+\r
+void sal_address_clean(SalAddress *addr){\r
+       osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params);\r
+       osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params);\r
+}\r
+\r
+char *sal_address_as_string(const SalAddress *u){\r
+       char *tmp,*ret;\r
+       osip_from_t *from=(osip_from_t *)u;\r
+       char *old_displayname=NULL;\r
+       /* hack to force use of quotes around the displayname*/\r
+       if (from->displayname!=NULL\r
+           && from->displayname[0]!='"'){\r
+               old_displayname=from->displayname;\r
+               from->displayname=osip_enquote(from->displayname);\r
+       }\r
+       osip_from_to_str(from,&tmp);\r
+       if (old_displayname!=NULL){\r
+               ms_free(from->displayname);\r
+               from->displayname=old_displayname;\r
+       }\r
+       ret=ms_strdup(tmp);\r
+       osip_free(tmp);\r
+       return ret;\r
+}\r
+\r
+char *sal_address_as_string_uri_only(const SalAddress *u){\r
+       char *tmp=NULL,*ret;\r
+       osip_uri_to_str(((osip_from_t*)u)->url,&tmp);\r
+       ret=ms_strdup(tmp);\r
+       osip_free(tmp);\r
+       return ret;\r
+}\r
+void sal_address_set_param(SalAddress *u,const char* name,const char* value) {\r
+       osip_uri_param_t *param=NULL;\r
+    osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,&param);\r
+    if (param == NULL){\r
+        osip_uri_uparam_add    (((osip_from_t*)u)->url,ms_strdup(name),value ? ms_strdup(value) : NULL);\r
+    } else {\r
+        osip_free(param->gvalue);\r
+        param->gvalue=value ? osip_strdup(value) : NULL;\r
+    }\r
+    \r
+}\r
+\r
+void sal_address_destroy(SalAddress *u){\r
+       osip_from_free((osip_from_t*)u);\r
+}\r
+\r
+void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) {\r
+       ctx->tcp_tls_keepalive = enabled;\r
+}\r
+\r
+void sal_set_keepalive_period(Sal *ctx,unsigned int value) {\r
+       switch (ctx->transport) {\r
+               case SalTransportUDP:\r
+                       ctx->keepalive_period = value;\r
+                       break;\r
+               case SalTransportTCP:\r
+               case SalTransportTLS:\r
+                       if (ctx->tcp_tls_keepalive) ctx->keepalive_period = value;\r
+                       else ctx->keepalive_period = -1;\r
+                       break;\r
+               default:\r
+                       break;\r
+       }\r
+       eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period);\r
+}\r
+unsigned int sal_get_keepalive_period(Sal *ctx) {\r
+       return ctx->keepalive_period;\r
+}\r
+\r
+const char * sal_address_get_port(const SalAddress *addr) {\r
+       const osip_from_t *u=(const osip_from_t*)addr;\r
+       return null_if_empty(u->url->port);\r
+}\r
+\r
+int sal_address_get_port_int(const SalAddress *uri) {\r
+       const char* port = sal_address_get_port(uri);\r
+       if (port != NULL) {\r
+               return atoi(port);\r
+       } else {\r
+               return 5060;\r
+       }\r
+}\r
+SalTransport sal_address_get_transport(const SalAddress* addr) {\r
+    const osip_from_t *u=(const osip_from_t*)addr;\r
+    osip_uri_param_t *transport_param=NULL;\r
+    osip_uri_uparam_get_byname(u->url,"transport",&transport_param);\r
+    if (transport_param == NULL){\r
+        return SalTransportUDP;\r
+    }  else {\r
+        return sal_transport_parse(transport_param->gvalue);\r
+    }\r
+}\r
+void sal_address_set_transport(SalAddress* addr,SalTransport transport) {\r
+    sal_address_set_param(addr, "transport", sal_transport_to_string(transport));\r
+}\r
+\r
+/* sends a reinvite. Local media description may have changed by application since call establishment*/\r
+int sal_call_update(SalOp *h, const char *subject){\r
+       int err=0;\r
+       osip_message_t *reinvite=NULL;\r
+\r
+       eXosip_lock();\r
+       if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){\r
+               eXosip_unlock();\r
+               return -1;\r
+       }\r
+       eXosip_unlock();\r
+       osip_message_set_subject(reinvite,subject);\r
+       osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");\r
+       if (h->base.contact){\r
+               _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free);\r
+               osip_message_set_contact(reinvite,h->base.contact);\r
+       }\r
+       if (h->base.root->session_expires!=0){\r
+               osip_message_set_header(reinvite, "Session-expires", "200");\r
+               osip_message_set_supported(reinvite, "timer");\r
+       }\r
+       if (h->base.local_media){\r
+               h->sdp_offering=TRUE;\r
+               set_sdp_from_desc(reinvite,h->base.local_media);\r
+       }else h->sdp_offering=FALSE;\r
+       eXosip_lock();\r
+       err = eXosip_call_send_request(h->did, reinvite);\r
+       eXosip_unlock();\r
+       return err;\r
+}\r
+\r
+void sal_reuse_authorization(Sal *ctx, bool_t value) {\r
+       ctx->reuse_authorization=value;\r
+}\r
+\r
+void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch){\r
+       MSList *elem=(MSList*)ch;\r
+       for (;elem!=NULL;elem=elem->next){\r
+               SalCustomHeader *it=(SalCustomHeader*)elem;\r
+               osip_message_set_header(msg,it->header_name,it->header_value);\r
+       }\r
+}\r
+\r
+SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg){\r
+       int i=0;\r
+       osip_header_t *header;\r
+       SalCustomHeader *ret=NULL;\r
+\r
+       while((header=osip_list_get(&msg->headers,i))!=NULL){\r
+               ret=sal_custom_header_append(ret,header->hname,header->hvalue);\r
+               i++;\r
+       }\r
+       return ret;\r
+}\r
+\r
index 81e3ed9a7902b10ad01cf4d9a8446ef1ba5d9efe..68a2d05ef845e5efc0063d0ab9acbf3d3f0bfd42 100644 (file)
@@ -94,6 +94,8 @@ void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev);
 SalOp * sal_find_out_subscribe(Sal *sal, int sid);
 SalOp * sal_find_in_subscribe(Sal *sal, int nid);
 void sal_exosip_fix_route(SalOp *op);
+void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch);
+SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg);
 
 void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*));
 
index 8156c3839a3128c4c221317322339b1a450919d2..4e0a9338d3441b93716925e9238eaaaa3d8e0024 100644 (file)
@@ -94,8 +94,7 @@ static inline char *my_ctime_r(const time_t *t, char *buf){
 
 int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){
        osip_message_t *sip=NULL;
-       time_t t;
-       time(&t);
+       time_t t=time(NULL);
        char buf[26];
 
        if(op->cid == -1)
@@ -111,6 +110,7 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
                eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op),
                        sal_op_get_from(op),sal_op_get_route(op));
                if (sip!=NULL){
+                       sal_exosip_add_custom_headers(sip,op->base.custom_headers);
                        osip_message_set_date(sip,my_ctime_r(&t,buf));
                        osip_message_set_content_type(sip,content_type);
                        if (msg) osip_message_set_body(sip,msg,strlen(msg));
index 20ff8181ff273b39bcffb5ed851a5430c96ac87b..7dc82920a1689d8a7ad87f7529fda65bc3deecdd 100644 (file)
@@ -51,17 +51,19 @@ void linphone_gtk_call_log_update(GtkWidget *w){
        for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){
                LinphoneCallLog *cl=(LinphoneCallLog*)logs->data;
                GtkTreeIter iter;
-               LinphoneAddress *la=cl->dir==LinphoneCallIncoming ? cl->from : cl->to;
+               LinphoneAddress *la=linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl);
                char *addr= linphone_address_as_string_uri_only (la);
                const char *display;
                gchar *logtxt, *minutes, *seconds;
                gchar quality[20];
                const char *status=NULL;
                gchar *start_date=NULL;
+               time_t start_date_time=linphone_call_log_get_start_date(cl);
+               int duration=linphone_call_log_get_duration(cl);
                
 #if GLIB_CHECK_VERSION(2,26,0)
-               if (cl->start_date_time){
-                       GDateTime *dt=g_date_time_new_from_unix_local(cl->start_date_time);
+               if (start_date_time){
+                       GDateTime *dt=g_date_time_new_from_unix_local(start_date_time);
                        start_date=g_date_time_format(dt,"%c");
                        g_date_time_unref(dt);
                }
@@ -73,10 +75,10 @@ void linphone_gtk_call_log_update(GtkWidget *w){
                        if (display==NULL)
                                display=linphone_address_get_domain (la);
                }
-               if (cl->quality!=-1){
-                       snprintf(quality,sizeof(quality),"%.1f",cl->quality);
-               }
-               switch(cl->status){
+               if (linphone_call_log_get_quality(cl)!=-1){
+                       snprintf(quality,sizeof(quality),"%.1f",linphone_call_log_get_quality(cl));
+               }else snprintf(quality,sizeof(quality)-1,"%s",_("n/a"));
+               switch(linphone_call_log_get_status(cl)){
                        case LinphoneCallAborted:
                                status=_("Aborted");
                        break;
@@ -90,21 +92,21 @@ void linphone_gtk_call_log_update(GtkWidget *w){
                        break;
                }
                minutes=g_markup_printf_escaped(
-                       ngettext("%i minute", "%i minutes", cl->duration/60),
-                       cl->duration/60);
+                       ngettext("%i minute", "%i minutes", duration/60),
+                       duration/60);
                seconds=g_markup_printf_escaped(
-                       ngettext("%i second", "%i seconds", cl->duration%60),
-                       cl->duration%60);
+                       ngettext("%i second", "%i seconds", duration%60),
+                       duration%60);
                if (status==NULL) logtxt=g_markup_printf_escaped(
                                _("<big><b>%s</b></big>\t<small><i>%s</i>\t"
                                        "<i>Quality: %s</i></small>\n%s\t%s %s\t"),
-                               display, addr, cl->quality!=-1 ? quality : _("n/a"),
-                               start_date ? start_date : cl->start_date, minutes, seconds);
+                               display, addr, quality ,
+                               start_date ? start_date : "", minutes, seconds);
                else logtxt=g_markup_printf_escaped(
                                _("<big><b>%s</b></big>\t<small><i>%s</i></small>\t"
                                        "\n%s\t%s"),
                                display, addr,
-                               start_date ? start_date : cl->start_date, status);
+                               start_date ? start_date : "", status);
                g_free(minutes);
                g_free(seconds);
                if (start_date) g_free(start_date);
@@ -113,7 +115,7 @@ void linphone_gtk_call_log_update(GtkWidget *w){
                GdkPixbuf *incoming = create_pixbuf("call_status_incoming.png");
                GdkPixbuf *outgoing = create_pixbuf("call_status_outgoing.png");
                gtk_list_store_set (store,&iter,
-                              0, cl->dir==LinphoneCallOutgoing ? outgoing : incoming,
+                              0, linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? outgoing : incoming,
                               1, logtxt,2,la,-1);
                ms_free(addr);
                g_free(logtxt);
index 68c86d38aac93f5fc45fa026f7658e25fe1ed1f9..60aa7cb1421734d9d8b5542c02192e1595edfa31 100644 (file)
@@ -101,7 +101,7 @@ static void linphone_gtk_in_call_set_animation_image(GtkWidget *callview, const
        GList *elem=gtk_container_get_children(GTK_CONTAINER(container));
        GtkWidget *image;
 
-    if (!is_stock){
+       if (!is_stock){
                if (image_name==NULL){
                        gtk_widget_hide(container);
                }
index fd8f21d7087ed2d5af18e4cd3a7db9bdf0008ed3..6251dea54272cf048c580e03a80c67d672367f2a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fd8f21d7087ed2d5af18e4cd3a7db9bdf0008ed3
+Subproject commit 6251dea54272cf048c580e03a80c67d672367f2a