]> sjero.net Git - linphone/commitdiff
implement notifications when doing transfers
authorSimon Morlat <simon.morlat@linphone.org>
Thu, 29 Mar 2012 13:09:52 +0000 (15:09 +0200)
committerSimon Morlat <simon.morlat@linphone.org>
Thu, 29 Mar 2012 13:09:52 +0000 (15:09 +0200)
13 files changed:
configure.ac
coreapi/callbacks.c
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/linphonecore.h
coreapi/presence.c
coreapi/private.h
coreapi/sal.h
coreapi/sal_eXosip2.c
gtk/incall_view.c
gtk/linphone.h
gtk/main.c
mediastreamer2

index 7a523eecb1b6eaf66cebb9c65c1b3f2e04e325a1..2bead21ddc9b1de1b86cbd8ad03eab28ac4b5830 100644 (file)
@@ -17,7 +17,7 @@ if test "$LINPHONE_EXTRA_VERSION" != "" ;then
        LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION}
 fi
 
-LIBLINPHONE_SO_CURRENT=4 dnl increment this number when you add/change/remove an interface
+LIBLINPHONE_SO_CURRENT=5 dnl increment this number when you add/change/remove an interface
 LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT
 LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface
 
index 5ffd43e44d3a1238f7811d4d7bf1c75cc483a6f5..8d41da1018c9ac72a732040e2ac8a0bc2542daaa 100644 (file)
@@ -323,6 +323,7 @@ static void call_accepted(SalOp *op){
            call->state==LinphoneCallOutgoingRinging ||
            call->state==LinphoneCallOutgoingEarlyMedia){
                linphone_call_set_state(call,LinphoneCallConnected,"Connected");
+               if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
        }
        if (md && !sal_media_description_empty(md)){
                if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
@@ -591,6 +592,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
        } else {
                linphone_call_set_state(call,LinphoneCallError,msg);
        }
+       if (call->referer && linphone_call_get_state(call->referer)==LinphoneCallPaused && call->referer->was_automatically_paused){
+               /*resume to the call that send us the refer automatically*/
+               linphone_core_resume_call(lc,call->referer);
+       }
 }
 
 static void call_released(SalOp *op){
@@ -744,12 +749,11 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){
                if (call->state!=LinphoneCallPaused){
                        ms_message("Automatically pausing current call to accept transfer.");
                        linphone_core_pause_call(lc,call);
+                       call->was_automatically_paused=TRUE;
                }
                linphone_core_start_refered_call(lc,call);
-               sal_call_accept_refer(op);
        }else if (lc->vtable.refer_received){
                lc->vtable.refer_received(lc,referto);
-               sal_call_accept_refer(op);
        }
 }
 
@@ -766,7 +770,7 @@ static void notify(SalOp *op, const char *from, const char *msg){
                lc->vtable.notify_recv(lc,call,from,msg);
 }
 
-static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
+static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg){
        LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
        linphone_notify_recv(lc,op,ss,status);
 }
@@ -795,6 +799,35 @@ static void ping_reply(SalOp *op){
        }
 }
 
+static void notify_refer(SalOp *op, SalReferStatus status){
+       LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
+       LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
+       LinphoneCallState cstate;
+       if (call==NULL) {
+               ms_warning("Receiving notify_refer for unknown call.");
+               return ;
+       }
+       switch(status){
+               case SalReferTrying:
+                       cstate=LinphoneCallOutgoingProgress;
+               break;
+               case SalReferSuccess:
+                       cstate=LinphoneCallConnected;
+               break;
+               case SalReferFailed:
+                       cstate=LinphoneCallError;
+               break;
+               default:
+                       cstate=LinphoneCallError;
+       }
+       if (lc->vtable.transfer_state_changed)
+               lc->vtable.transfer_state_changed(lc,call,cstate);
+       if (cstate==LinphoneCallConnected){
+               /*automatically terminate the call as the transfer is complete.*/
+               linphone_core_terminate_call(lc,call);
+       }
+}
+
 SalCallbacks linphone_sal_callbacks={
        call_received,
        call_ringing,
@@ -814,6 +847,7 @@ SalCallbacks linphone_sal_callbacks={
        text_received,
        notify,
        notify_presence,
+       notify_refer,
        subscribe_received,
        subscribe_closed,
        ping_reply
index 61a528d2a690eadf192648e71ba8a0acca58ae40..433d0ce26606f0139cd0576fef238181e6bf2f45 100644 (file)
@@ -332,6 +332,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
        discover_mtu(lc,linphone_address_get_domain (to));
        if (params->referer){
                sal_call_set_referer(call->op,params->referer->op);
+               call->referer=linphone_call_ref(params->referer);
        }
        return call;
 }
@@ -401,6 +402,10 @@ static void linphone_call_set_terminated(LinphoneCall *call){
                linphone_core_stop_dtmf(lc);
                call->ringing_beep=FALSE;
        }
+       if (call->referer){
+               linphone_call_unref(call->referer);
+               call->referer=NULL;
+       }
 }
 
 void linphone_call_fix_call_parameters(LinphoneCall *call){
index bee7ad5fe1fabba7b51e7330df239f6175215156..904f6a6c8c3fc7d0d4e9090cc41a57ae364b6b72 100644 (file)
@@ -1943,12 +1943,20 @@ const char * linphone_core_get_route(LinphoneCore *lc){
 void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){
        if (call->refer_pending){
                LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc);
+               LinphoneCall *newcall;
                cp->has_video &= !!lc->video_policy.automatically_initiate;
                cp->referer=call;
                ms_message("Starting new call to refered address %s",call->refer_to);
                call->refer_pending=FALSE;
-               linphone_core_invite_with_params(lc,call->refer_to,cp);
+               newcall=linphone_core_invite_with_params(lc,call->refer_to,cp);
                linphone_call_params_destroy(cp);
+               if (newcall) linphone_core_notify_refer_state(lc,call,newcall);
+       }
+}
+
+void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall){
+       if (referer->op!=NULL){
+               sal_call_notify_refer_state(referer->op,newcall ? newcall->op : NULL);
        }
 }
 
index b7ceb87ddc12b1ad91825a67ee26013ec86eac32..4581d24fa92dbde61da58b270fbd359010180e7b 100644 (file)
@@ -616,7 +616,9 @@ typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to);
 typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf);
 /** Callback prototype */
 typedef void (*CallFirstVideoFrameCb)(struct _LinphoneCore *lc, LinphoneCall *call);
-    
+/** Callback prototype for in progress transfers. The new_call_state is the state of the call resulting of the transfer, at the other party. */
+typedef void (*LinphoneTransferStateChanged)(struct _LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
+
 /**
  * This structure holds all callbacks that the application should implement.
  *  None is mandatory.
@@ -632,6 +634,9 @@ typedef struct _LinphoneVTable{
        TextMessageReceived text_received; /**< A text message has been received */
        DtmfReceived dtmf_received; /**< A dtmf has been received received */
        ReferReceived refer_received; /**< An out of call refer was received */
+       CallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
+    CallFirstVideoFrameCb call_first_video_frame; /**<Notifies on first successful video frame decoding */
+       LinphoneTransferStateChanged transfer_state_changed; /**<Notifies when a transfer is in progress */
        BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
        NotifyReceivedCb notify_recv; /**< Other notifications*/
        DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/
@@ -639,8 +644,6 @@ typedef struct _LinphoneVTable{
        DisplayMessageCb display_warning;/** Callback to display a warning to the user */
        DisplayUrlCb display_url;
        ShowInterfaceCb show; /**< Notifies the application that it should show up*/
-       CallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
-    CallFirstVideoFrameCb call_first_video_frame; /** Notifies on first successful video frame decoding */
 } LinphoneCoreVTable;
 
 /**
index d97f4ed9419548bb0d34a95e1e2ed872d4f36ba8..ca63572588c764cfcde05fa5b7ff39f8d6e13cc9 100644 (file)
@@ -101,7 +101,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
        ms_free(tmp);
 }
 
-void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus sal_status){
+void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus sal_status){
        char *tmp;
        LinphoneFriend *lf;
        LinphoneAddress *friend=NULL;
index ab317c981850205d8eb725bed7c5d2879b8fabb0..c77b66d1b1bddbe99a196341742cb334d297645e 100644 (file)
@@ -84,6 +84,7 @@ struct _LinphoneCall
        SalMediaDescription *localdesc;
        SalMediaDescription *resultdesc;
        LinphoneCallDir dir;
+       LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/
        struct _RtpProfile *audio_profile;
        struct _RtpProfile *video_profile;
        struct _LinphoneCallLog *log;
@@ -122,6 +123,7 @@ struct _LinphoneCall
        bool_t audiostream_encrypted;
        bool_t auth_token_verified;
        bool_t defer_update;
+       bool_t was_automatically_paused;
 };
 
 
@@ -193,7 +195,7 @@ SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os);
 void linphone_process_authentication(LinphoneCore* lc, SalOp *op);
 void linphone_authentication_ok(LinphoneCore *lc, SalOp *op);
 void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from);
-void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, SalPresenceStatus status);
+void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status);
 void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op);
 
 void linphone_subscription_answered(LinphoneCore *lc, SalOp *op);
@@ -549,6 +551,7 @@ void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted);
 void linphone_call_remove_from_conf(LinphoneCall *call);
 void linphone_core_conference_check_uninit(LinphoneCore *lc);
 bool_t linphone_core_sound_resources_available(LinphoneCore *lc);
+void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall);
 
 void __linphone_core_invalidate_registers(LinphoneCore* lc);
 
index 1ae18a9d4ebe4bdd37663f87446c0b4ff588b04e..c4fabc6baff35c99ee9bd05a12cc2ca93a8c5051 100644 (file)
@@ -206,10 +206,16 @@ typedef enum SalPresenceStatus{
        SalPresenceAltService,
 }SalPresenceStatus;
 
-typedef enum SalSubscribeState{
+typedef enum SalReferStatus{
+       SalReferTrying,
+       SalReferSuccess,
+       SalReferFailed
+}SalReferStatus;
+
+typedef enum SalSubscribeStatus{
        SalSubscribeActive,
        SalSubscribeTerminated
-}SalSubscribeState;
+}SalSubscribeStatus;
 
 typedef void (*SalOnCallReceived)(SalOp *op);
 typedef void (*SalOnCallRinging)(SalOp *op);
@@ -227,8 +233,9 @@ typedef void (*SalOnVfuRequest)(SalOp *op);
 typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf);
 typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto);
 typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg);
-typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *value);
-typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg);
+typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event);
+typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state);
+typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg);
 typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from);
 typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from);
 typedef void (*SalOnPingReply)(SalOp *salop);
@@ -252,6 +259,7 @@ typedef struct SalCallbacks{
        SalOnTextReceived text_received;
        SalOnNotify notify;
        SalOnNotifyPresence notify_presence;
+       SalOnNotifyRefer notify_refer;
        SalOnSubscribeReceived subscribe_received;
        SalOnSubscribeClosed subscribe_closed;
        SalOnPingReply ping_reply;
@@ -339,6 +347,7 @@ int sal_call_terminate(SalOp *h);
 bool_t sal_call_autoanswer_asked(SalOp *op);
 void sal_call_send_vfu_request(SalOp *h);
 int sal_call_is_offerer(const SalOp *h);
+int sal_call_notify_refer_state(SalOp *h, SalOp *newcall);
 
 /*Registration*/
 int sal_register(SalOp *op, const char *proxy, const char *from, int expires);
index 6d66bf4c42d8f1ff8ea911d5f2587fe44a627dd0..a89a8a13c5e7b0bd264f63f0a1938b0fdff23ab7 100644 (file)
@@ -728,6 +728,45 @@ int sal_call_set_referer(SalOp *h, SalOp *refered_call){
        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_error("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){
+                               send_notify_for_refer(h->did,"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;
        
@@ -748,26 +787,6 @@ int sal_ping(SalOp *op, const char *from, const char *to){
        return -1;
 }
 
-int sal_call_accept_refer(SalOp *op){
-       osip_message_t *msg=NULL;
-       int err=0;
-       eXosip_lock();
-       err = eXosip_call_build_notify(op->did,EXOSIP_SUBCRSTATE_ACTIVE,&msg);
-       if(msg != NULL)
-       {
-               osip_message_set_header(msg,(const char *)"event","refer");
-               osip_message_set_content_type(msg,"message/sipfrag");
-               osip_message_set_body(msg,"SIP/2.0 100 Trying",sizeof("SIP/2.0 100 Trying"));
-               eXosip_call_send_request(op->did,msg);
-       }
-       else
-       {
-               ms_error("could not get a notify built\n");
-       }
-       eXosip_unlock();
-       return err;
-}
-
 int sal_call_refer(SalOp *h, const char *refer_to){
        osip_message_t *msg=NULL;
        int err=0;
@@ -1517,6 +1536,51 @@ static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){
        }
 }
 
+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){
@@ -1559,22 +1623,7 @@ static void call_message_new(Sal *sal, eXosip_event_t *ev){
                        ms_message("Receiving REFER request !");
                        process_refer(sal,op,ev);
                }else if(MSG_IS_NOTIFY(ev->request)){
-                       osip_header_t *h=NULL;
-                       char *from=NULL;
-                       SalOp *op=find_op(sal,ev);
-
-                       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)
-                               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);
+                       process_notify(sal,ev);
                }else if (MSG_IS_OPTIONS(ev->request)){
                        eXosip_lock();
                        eXosip_call_build_answer(ev->tid,200,&ans);
index d693ac149acb60b0bd8889a68d91146765a18870..d19dba8c2c400f1f713afd71ccdd5742906b3952 100644 (file)
@@ -579,6 +579,28 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
                linphone_gtk_terminate_conference_participant(call);
 }
 
+void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate){
+       GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
+       if (callview){
+               GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
+               const char *transfer_status="unknown";
+               switch(cstate){
+                       case LinphoneCallOutgoingProgress:
+                               transfer_status=_("Transfer in progress");
+                       break;
+                       case LinphoneCallConnected:
+                               transfer_status=_("Transfer done.");
+                       break;
+                       case LinphoneCallError:
+                               transfer_status=_("Transfer failed.");
+                       break;
+                       default:
+                       break;
+               }
+               gtk_label_set_text(GTK_LABEL(duration),transfer_status);
+       }
+}
+
 void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){
        g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active));
        if (active){
index 7074bc87d551cde92d81edb6da1c142adbef0879..d4cafe28f359acad9ade88de52be65c4152f4e0b 100644 (file)
@@ -107,6 +107,7 @@ void linphone_gtk_in_call_view_update_duration(LinphoneCall *call);
 void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg);
 void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call);
 void linphone_gtk_in_call_view_set_paused(LinphoneCall *call);
+void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate);
 void linphone_gtk_mute_clicked(GtkButton *button);
 void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive);
 void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon);
index 60c4556d7eff165493495371de577c1a613524f3..8191952684d3996edb0658dc2e9e1f2b35fafb2b 100644 (file)
@@ -63,6 +63,7 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch
 static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
 static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
 static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token);
+static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate);
 static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
 static void linphone_gtk_status_icon_set_blinking(gboolean val);
 
@@ -225,6 +226,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
        vtable.refer_received=linphone_gtk_refer_received;
        vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
        vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
+       vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
 
        linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
        the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
@@ -1133,6 +1135,10 @@ static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall
        linphone_gtk_in_call_view_show_encryption(call);
 }
 
+static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate){
+       linphone_gtk_in_call_view_set_transfer_status(call,cstate);
+}
+
 static void update_registration_status(LinphoneProxyConfig *cfg, LinphoneRegistrationState rs){
        GtkComboBox *box=GTK_COMBO_BOX(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"identities"));
        GtkTreeModel *model=gtk_combo_box_get_model(box);
index 9d722a1456c8574b385fac0eadf4ad6a4067637b..1b517a0bc1d6559267143130d137d0252a05f752 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9d722a1456c8574b385fac0eadf4ad6a4067637b
+Subproject commit 1b517a0bc1d6559267143130d137d0252a05f752