]> sjero.net Git - linphone/blobdiff - coreapi/friend.c
Add fmtp parameters to opus payload to enable FEC and DTX
[linphone] / coreapi / friend.c
index 08f072de31b8309b6f86750d0273360f7fd4241b..c6dee2440a8d28019c003893123cc2dfde218b0a 100644 (file)
 
 #include "linphonecore.h"
 #include "private.h"
-#include <eXosip2/eXosip.h>
-#include <osipparser2/osip_message.h>
 #include "lpconfig.h"
 
 const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
        const char *str=NULL;
        switch(ss){
-               case LINPHONE_STATUS_UNKNOWN:
-               str=_("Unknown");
-               break;
-               case LINPHONE_STATUS_ONLINE:
+               case LinphoneStatusOnline:
                str=_("Online");
                break;
-               case LINPHONE_STATUS_BUSY:
+               case LinphoneStatusBusy:
                str=_("Busy");
                break;
-               case LINPHONE_STATUS_BERIGHTBACK:
+               case LinphoneStatusBeRightBack:
                str=_("Be right back");
                break;
-               case LINPHONE_STATUS_AWAY:
+               case LinphoneStatusAway:
                str=_("Away");
                break;
-               case LINPHONE_STATUS_ONTHEPHONE:
+               case LinphoneStatusOnThePhone:
                str=_("On the phone");
                break;
-               case LINPHONE_STATUS_OUTTOLUNCH:
+               case LinphoneStatusOutToLunch:
                str=_("Out to lunch");
                break;
-               case LINPHONE_STATUS_NOT_DISTURB:
+               case LinphoneStatusDoNotDisturb:
                str=_("Do not disturb");
                break;
-               case LINPHONE_STATUS_MOVED:
+               case LinphoneStatusMoved:
                str=_("Moved");
                break;
-               case LINPHONE_STATUS_ALT_SERVICE:
+               case LinphoneStatusAltService:
                str=_("Using another messaging service");
                break;
-               case LINPHONE_STATUS_OFFLINE:
+               case LinphoneStatusOffline:
                str=_("Offline");
                break;
-               case LINPHONE_STATUS_PENDING:
+               case LinphoneStatusPending:
                str=_("Pending");
                break;
-               case LINPHONE_STATUS_CLOSED:
-               str=_("Closed");
-               break;
                default:
                str=_("Unknown-bug");
        }
        return str;
 }
 
-static int friend_data_compare(const void * a, const void * b, void * data){
+static int friend_compare(const void * a, const void * b){
        LinphoneAddress *fa=((LinphoneFriend*)a)->uri;
        LinphoneAddress *fb=((LinphoneFriend*)b)->uri;
-       const char *ua,*ub;
-       ua=linphone_address_get_username(fa);
-       ub=linphone_address_get_username(fb);
-       if (ua!=NULL && ub!=NULL) {
-               //printf("Comparing usernames %s,%s\n",ua,ub);
-               return strcasecmp(ua,ub);
-       }
-       else {
-               /* compare hosts*/
-               ua=linphone_address_get_domain(fa);
-               ub=linphone_address_get_domain(fb);
-               if (ua!=NULL && ub!=NULL){
-                       int ret=strcasecmp(ua,ub);
-                       //printf("Comparing hostnames %s,%s,res=%i\n",ua,ub,ret);
-                       return ret;
-               }
-               else return -1;
-       }
-}
-
-static int friend_compare(const void * a, const void * b){
-       return friend_data_compare(a,b,NULL);
+       if (linphone_address_weak_equal (fa,fb)) return 0;
+       return 1;
 }
 
 
@@ -114,20 +86,20 @@ MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *friend, Linphone
        return res;
 }
 
-LinphoneFriend *linphone_find_friend_by_nid(MSList *l, int nid){
+LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){
        MSList *elem;
        for (elem=l;elem!=NULL;elem=elem->next){
                LinphoneFriend *lf=(LinphoneFriend*)elem->data;
-               if (lf->nid==nid) return lf;
+               if (lf->insub==op) return lf;
        }
        return NULL;
 }
 
-LinphoneFriend *linphone_find_friend_by_sid(MSList *l, int sid){
+LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){
        MSList *elem;
        for (elem=l;elem!=NULL;elem=elem->next){
                LinphoneFriend *lf=(LinphoneFriend*)elem->data;
-               if (lf->sid==sid) return lf;
+               if (lf->outsub==op) return lf;
        }
        return NULL;
 }
@@ -136,45 +108,66 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
        char *friend=NULL;
        const char *route=NULL;
        const char *from=NULL;
-       osip_message_t *msg=NULL;
+       const char *fixed_contact=NULL;
+       LinphoneProxyConfig *cfg;
+       
        friend=linphone_address_as_string(fr->uri);
-       if (fr->proxy!=NULL){
-               route=fr->proxy->reg_route;
-               from=fr->proxy->reg_identity;
+       cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr));
+       if (cfg!=NULL){
+               route=linphone_proxy_config_get_route(cfg);
+               from=linphone_proxy_config_get_identity(cfg);
+               if (cfg->op){
+                       fixed_contact=sal_op_get_contact(cfg->op);
+                       if (fixed_contact) {
+                               ms_message("Contact for subscribe has been fixed using proxy to %s",fixed_contact);
+                       }
+               }
        }else from=linphone_core_get_primary_contact(fr->lc);
-       if (fr->sid<0){
+       if (fr->outsub==NULL){
                /* people for which we don't have yet an answer should appear as offline */
-               fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr,friend,_("Gone"),"sip-closed.png");
-       }
-       eXosip_lock();
-       eXosip_subscribe_build_initial_request(&msg,friend,from,route,"presence",600);
-       eXosip_subscribe_send_initial_request(msg);
-       eXosip_unlock();
+               fr->status=LinphoneStatusOffline;
+               /*
+               if (fr->lc->vtable.notify_recv)
+                       fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
+                */
+       }else{
+               sal_op_release(fr->outsub);
+               fr->outsub=NULL;
+       }
+       fr->outsub=sal_op_new(fr->lc->sal);
+       sal_op_set_route(fr->outsub,route);
+       sal_op_set_contact(fr->outsub,fixed_contact);
+       sal_subscribe_presence(fr->outsub,from,friend);
+       fr->subscribe_active=TRUE;
        ms_free(friend);
 }
 
-
 LinphoneFriend * linphone_friend_new(){
        LinphoneFriend *obj=ms_new0(LinphoneFriend,1);
-       obj->out_did=-1;
-       obj->in_did=-1;
-       obj->nid=-1;
-       obj->sid=-1;
        obj->pol=LinphoneSPAccept;
-       obj->status=LINPHONE_STATUS_OFFLINE;
+       obj->status=LinphoneStatusOffline;
        obj->subscribe=TRUE;
        return obj;     
 }
 
 LinphoneFriend *linphone_friend_new_with_addr(const char *addr){
+       LinphoneAddress* linphone_address = linphone_address_new(addr);
+       if (linphone_address == NULL) {
+               ms_error("Cannot create friend for address [%s]",addr?addr:"null");
+               return NULL;
+       }
        LinphoneFriend *fr=linphone_friend_new();
-       if (linphone_friend_set_sip_addr(fr,addr)<0){
+       if (linphone_friend_set_addr(fr,linphone_address)<0){
                linphone_friend_destroy(fr);
                return NULL;
        }
        return fr;
 }
 
+bool_t linphone_friend_in_list(const LinphoneFriend *lf){
+       return lf->lc!=NULL;
+}
+
 void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result){
        LinphoneAddress *fr=NULL;
        *result=NULL;
@@ -193,6 +186,7 @@ void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char
                        /*try adding domain part from default current proxy*/
                        LinphoneAddress * id=linphone_address_new(linphone_core_get_identity(lc));
                        if (id!=NULL){
+                               linphone_address_set_display_name(id,NULL);
                                linphone_address_set_username(id,uri);
                                *result=linphone_address_as_string(id);
                                linphone_address_destroy(id);
@@ -208,12 +202,9 @@ void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char
        linphone_address_destroy(fr);
 }
 
-int linphone_friend_set_sip_addr(LinphoneFriend *lf, const char *addr){
-       LinphoneAddress *fr=linphone_address_new(addr);
-       if (fr==NULL) {
-               ms_warning("Invalid friend sip uri: %s",addr);
-               return -1;
-       }
+int linphone_friend_set_addr(LinphoneFriend *lf, const LinphoneAddress *addr){
+       LinphoneAddress *fr=linphone_address_clone(addr);
+       linphone_address_clean(fr);
        if (lf->uri!=NULL) linphone_address_destroy(lf->uri);   
        lf->uri=fr;
        return 0;
@@ -229,7 +220,7 @@ int linphone_friend_set_name(LinphoneFriend *lf, const char *name){
        return 0;
 }
 
-int linphone_friend_send_subscribe(LinphoneFriend *fr, bool_t val){
+int linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t val){
        fr->subscribe=val;
        return 0;
 }
@@ -240,335 +231,90 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri
        return 0;
 }
 
-int linphone_friend_set_proxy(LinphoneFriend *fr, struct _LinphoneProxyConfig *cfg){
-       fr->proxy=cfg;
-       return 0;
+SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){
+       switch(os){
+               case LinphoneStatusOffline:
+                       return SalPresenceOffline;
+               break;
+               case LinphoneStatusOnline:
+                       return SalPresenceOnline;
+               break;
+               case LinphoneStatusBusy:
+                       return SalPresenceBusy;
+               break;
+               case LinphoneStatusBeRightBack:
+                       return SalPresenceBerightback;
+               break;
+               case LinphoneStatusAway:
+                       return SalPresenceAway;
+               break;
+               case LinphoneStatusOnThePhone:
+                       return SalPresenceOnthephone;
+               break;
+               case LinphoneStatusOutToLunch:
+                       return SalPresenceOuttolunch;
+               break;
+               case LinphoneStatusDoNotDisturb:
+                       return SalPresenceDonotdisturb;
+               break;
+               case LinphoneStatusMoved:
+                       return SalPresenceMoved;
+               break;
+               case LinphoneStatusAltService:
+                       return SalPresenceAltService;
+               break;
+               case LinphoneStatusPending:
+                       return SalPresenceOffline;
+               break;
+               default:
+                       return SalPresenceOffline;
+               break;
+       }
+       return SalPresenceOffline;
 }
 
-void linphone_friend_set_sid(LinphoneFriend *lf, int sid){
-       lf->sid=sid;
-}
-void linphone_friend_set_nid(LinphoneFriend *lf, int nid){
-       lf->nid=nid;
-       lf->inc_subscribe_pending=TRUE;
+void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){
+       char *addr=linphone_address_as_string(linphone_friend_get_address(lf));
+       ms_message("Want to notify %s, insub=%p",addr,lf->insub);
+       ms_free(addr);
+       if (lf->insub!=NULL){
+               sal_notify_presence(lf->insub,linphone_online_status_to_sal(os),NULL);
+       }
 }
 
-void add_presence_body(osip_message_t *notify, LinphoneOnlineStatus online_status)
-{
-       char buf[1000];
-#ifdef SUPPORT_MSN
-       int atom_id = 1000;
-#endif
-       char *contact_info;
-
-       osip_contact_t *ct=NULL;
-       osip_message_get_contact(notify,0,&ct);
-       osip_contact_to_str(ct,&contact_info);
-
-#ifdef SUPPORT_MSN
-
-  if (online_status==LINPHONE_STATUS_ONLINE)
-    {
-      sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"open\" />\n\
-<msnsubstatus substatus=\"online\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
-    }
-  else if (online_status==LINPHONE_STATUS_BUSY)
-    {
-      sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inuse\" />\n\
-<msnsubstatus substatus=\"busy\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
-    }
-  else if (online_status==LINPHONE_STATUS_BERIGHTBACK)
-    {
-      sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inactive\" />\n\
-<msnsubstatus substatus=\"berightback\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
-    }
-  else if (online_status==LINPHONE_STATUS_AWAY)
-    {
-      sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inactive\" />\n\
-<msnsubstatus substatus=\"away\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
-    }
-  else if (online_status==LINPHONE_STATUS_ONTHEPHONE)
-    {
-      sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inuse\" />\n\
-<msnsubstatus substatus=\"onthephone\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
-    }
-  else if (online_status==LINPHONE_STATUS_OUTTOLUNCH)
-    {
-      sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inactive\" />\n\
-<msnsubstatus substatus=\"outtolunch\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-
-    }
-  else
-    {
-      sprintf(buf, "<?xml version=\"1.0\"?>\n\
-<!DOCTYPE presence\n\
-PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
-<presence>\n\
-<presentity uri=\"%s;method=SUBSCRIBE\" />\n\
-<atom id=\"%i\">\n\
-<address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
-<status status=\"inactive\" />\n\
-<msnsubstatus substatus=\"away\" />\n\
-</address>\n\
-</atom>\n\
-</presence>", contact_info, atom_id, contact_info);
-    }
-
-  osip_message_set_body(notify, buf, strlen(buf));
-  osip_message_set_content_type(notify, "application/xpidf+xml");
-#else
-
-  if (online_status==LINPHONE_STATUS_ONLINE)
-    {
-      sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-          entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>online</note>\n\
-</tuple>\n\
-</presence>",
-             contact_info, contact_info);
-    }
-  else if (online_status==LINPHONE_STATUS_BUSY)
-    {
-      sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-          xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
-          entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
-  <es:activity>busy</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>busy</note>\n\
-</tuple>\n\
-</presence>",
-             contact_info, contact_info);
-    }
-  else if (online_status==LINPHONE_STATUS_BERIGHTBACK)
-    {
-      sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-          xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
-          entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
-  <es:activity>in-transit</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>be right back</note>\n\
-</tuple>\n\
-</presence>",
-             contact_info, contact_info);
-    }
-  else if (online_status==LINPHONE_STATUS_AWAY)
-    {
-      sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-          xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
-          entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
-  <es:activity>away</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>away</note>\n\
-</tuple>\n\
-</presence>",
-             contact_info, contact_info);
-    }
-  else if (online_status==LINPHONE_STATUS_ONTHEPHONE)
-    {
-      sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-          xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
-          entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
-  <es:activity>on-the-phone</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>on the phone</note>\n\
-</tuple>\n\
-</presence>",
-             contact_info, contact_info);
-    }
-  else if (online_status==LINPHONE_STATUS_OUTTOLUNCH)
-    {
-      sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-          xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
-          entity=\"%s\">\n\
-<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>open</basic>\n\
-<es:activities>\n\
-  <es:activity>meal</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-<contact priority=\"0.8\">%s</contact>\n\
-<note>out to lunch</note>\n\
-</tuple>\n\
-</presence>",
-             contact_info, contact_info);
-    }
-  else
-    {
-      /* */
-      sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
-<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
-xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
-entity=\"%s\">\n%s",
-             contact_info,
-"<tuple id=\"sg89ae\">\n\
-<status>\n\
-<basic>closed</basic>\n\
-<es:activities>\n\
-  <es:activity>permanent-absence</es:activity>\n\
-</es:activities>\n\
-</status>\n\
-</tuple>\n\
-\n</presence>\n");
-    }
-  osip_message_set_body(notify, buf, strlen(buf));
-  osip_message_set_content_type(notify, "application/pidf+xml");
-
-#endif
-       osip_free(contact_info);
-}
-
-
-void linphone_friend_notify(LinphoneFriend *lf, int ss, LinphoneOnlineStatus os){
-       //printf("Wish to notify %p, lf->nid=%i\n",lf,lf->nid);
-       if (lf->in_did!=-1){
-               osip_message_t *msg=NULL;
-               const char *identity;
-               if (lf->proxy!=NULL) identity=lf->proxy->reg_identity;
-               else identity=linphone_core_get_primary_contact(lf->lc);
-               eXosip_lock();
-               eXosip_insubscription_build_notify(lf->in_did,ss,0,&msg);
-               if (msg!=NULL){
-                       osip_message_set_contact(msg,identity);
-                       add_presence_body(msg,os);
-                       eXosip_insubscription_send_request(lf->in_did,msg);
-               }else ms_error("could not create notify for incoming subscription.");
-               eXosip_unlock();
+static void linphone_friend_unsubscribe(LinphoneFriend *lf){
+       if (lf->outsub!=NULL) {
+               sal_unsubscribe(lf->outsub);
+               lf->subscribe_active=FALSE;
        }
 }
 
-static void linphone_friend_unsubscribe(LinphoneFriend *lf){
-       if (lf->out_did!=-1) {
-               osip_message_t *msg=NULL;
-               eXosip_lock();
-               eXosip_subscribe_build_refresh_request(lf->out_did,&msg);
-               if (msg){
-                       osip_message_set_expires(msg,"0");
-                       eXosip_subscribe_send_refresh_request(lf->out_did,msg);
-               }else ms_error("Could not build subscribe refresh request !");
-               eXosip_unlock();
+void linphone_friend_close_subscriptions(LinphoneFriend *lf){
+       linphone_friend_unsubscribe(lf);
+       if (lf->insub){
+               sal_notify_close(lf->insub);
+               
        }
 }
 
 void linphone_friend_destroy(LinphoneFriend *lf){
-       linphone_friend_notify(lf,EXOSIP_SUBCRSTATE_TERMINATED,LINPHONE_STATUS_CLOSED);
-       linphone_friend_unsubscribe(lf);
+       if (lf->insub) {
+               sal_op_release(lf->insub);
+               lf->insub=NULL;
+       }
+       if (lf->outsub){
+               sal_op_release(lf->outsub);
+               lf->outsub=NULL;
+       }
        if (lf->uri!=NULL) linphone_address_destroy(lf->uri);
        if (lf->info!=NULL) buddy_info_free(lf->info);
        ms_free(lf);
 }
 
-void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, LinphoneProxyConfig *cfg){
-       if (lf->proxy==cfg){
-               lf->proxy=NULL;
-       }
-}
-
-const LinphoneAddress *linphone_friend_get_uri(const LinphoneFriend *lf){
+const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf){
        return lf->uri;
 }
 
-
 bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){
        return lf->subscribe;
 }
@@ -597,26 +343,27 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
        if (fr->inc_subscribe_pending){
                switch(fr->pol){
                        case LinphoneSPWait:
-                               linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_PENDING,LINPHONE_STATUS_PENDING);
+                               linphone_friend_notify(fr,LinphoneStatusPending);
                                break;
                        case LinphoneSPAccept:
                                if (fr->lc!=NULL)
                                  {
-                                       linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_ACTIVE,fr->lc->presence_mode);
+                                       linphone_friend_notify(fr,fr->lc->presence_mode);
                                  }
                                break;
                        case LinphoneSPDeny:
-                               linphone_friend_notify(fr,EXOSIP_SUBCRSTATE_TERMINATED,LINPHONE_STATUS_CLOSED);
+                               linphone_friend_notify(fr,LinphoneStatusOffline);
                                break;
                }
                fr->inc_subscribe_pending=FALSE;
        }
-       if (fr->subscribe && fr->out_did==-1){
-               
+       if (fr->subscribe && fr->subscribe_active==FALSE){
+               ms_message("Sending a new SUBSCRIBE");
                __linphone_friend_do_subscribe(fr);
        }
        ms_message("linphone_friend_apply() done.");
        lc->bl_refresh=TRUE;
+       fr->commit=FALSE;
 }
 
 void linphone_friend_edit(LinphoneFriend *fr){
@@ -632,20 +379,38 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf)
 {
        ms_return_if_fail(lf->lc==NULL);
        ms_return_if_fail(lf->uri!=NULL);
+       if (ms_list_find(lc->friends,lf)!=NULL){
+               char *tmp=NULL;
+               const LinphoneAddress *addr=linphone_friend_get_address(lf);
+               if (addr) tmp=linphone_address_as_string(addr);
+               ms_warning("Friend %s already in list, ignored.", tmp ? tmp : "unknown");
+               if (tmp) ms_free(tmp);
+               return ;
+       }
        lc->friends=ms_list_append(lc->friends,lf);
-       linphone_friend_apply(lf,lc);
+       if ( linphone_core_ready(lc)) linphone_friend_apply(lf,lc);
+       else lf->commit=TRUE;
        return ;
 }
 
 void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){
        MSList *el=ms_list_find(lc->friends,(void *)fl);
        if (el!=NULL){
-               lc->friends=ms_list_remove_link(lc->friends,el);
                linphone_friend_destroy((LinphoneFriend*)el->data);
+               lc->friends=ms_list_remove_link(lc->friends,el);
                linphone_core_write_friends_config(lc);
        }
 }
 
+void linphone_core_send_initial_subscribes(LinphoneCore *lc){
+       const MSList *elem;
+       for(elem=lc->friends;elem!=NULL;elem=elem->next){
+               LinphoneFriend *f=(LinphoneFriend*)elem->data;
+               if (f->commit)
+                       linphone_friend_apply(f,lc);
+       }
+}
+
 void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key){
        if (lf->refkey!=NULL){
                ms_free(lf->refkey);
@@ -667,16 +432,22 @@ static bool_t username_match(const char *u1, const char *u2){
        return FALSE;
 }
 
-LinphoneFriend *linphone_core_get_friend_by_uri(const LinphoneCore *lc, const char *uri){
+LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *uri){
        LinphoneAddress *puri=linphone_address_new(uri);
        const MSList *elem;
-       const char *username=linphone_address_get_username(puri);
-       const char *domain=linphone_address_get_domain(puri);
+       const char *username;
+       const char *domain;
        LinphoneFriend *lf=NULL;
                
        if (puri==NULL){
                return NULL;
        }
+       username=linphone_address_get_username(puri);
+       domain=linphone_address_get_domain(puri);
+       if (domain==NULL) {
+               linphone_address_destroy(puri);
+               return NULL;
+       }
        for(elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){
                lf=(LinphoneFriend*)elem->data;
                const char *it_username=linphone_address_get_username(lf->uri);
@@ -752,10 +523,6 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde
        a=lp_config_get_int(config,item,"subscribe",0);
        linphone_friend_send_subscribe(lf,a);
                
-       a=lp_config_get_int(config,item,"proxy",-1);
-       if (a!=-1) {
-               linphone_friend_set_proxy(lf,__index_to_proxy(lc,a));
-       }
        linphone_friend_set_ref_key(lf,lp_config_get_string(config,item,"refkey",NULL));
        return lf;
 }
@@ -779,7 +546,6 @@ const char *__policy_enum_to_str(LinphoneSubscribePolicy pol){
 void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, int index){
        char key[50];
        char *tmp;
-       int a;
        const char *refkey;
        
        sprintf(key,"friend_%i",index);
@@ -794,14 +560,10 @@ void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf,
                        return;
                }
                lp_config_set_string(config,key,"url",tmp);
-               osip_free(tmp);
+               ms_free(tmp);
        }
        lp_config_set_string(config,key,"pol",__policy_enum_to_str(lf->pol));
        lp_config_set_int(config,key,"subscribe",lf->subscribe);
-       if (lf->proxy!=NULL){
-               a=ms_list_index(lf->lc->sip_conf.proxies,lf->proxy);
-               lp_config_set_int(config,key,"proxy",a);
-       }else lp_config_set_int(config,key,"proxy",-1);
 
        refkey=linphone_friend_get_ref_key(lf);
        if (refkey){
@@ -813,7 +575,7 @@ void linphone_core_write_friends_config(LinphoneCore* lc)
 {
        MSList *elem;
        int i;
-       if (!lc->ready) return; /*dont write config when reading it !*/
+       if (! linphone_core_ready(lc)) return; /*dont write config when reading it !*/
        for (elem=lc->friends,i=0; elem!=NULL; elem=ms_list_next(elem),i++){
                linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)elem->data,i);
        }