]> sjero.net Git - linphone/blob - coreapi/sal_eXosip2_presence.c
support for in call MESSAGEs
[linphone] / coreapi / sal_eXosip2_presence.c
1 /*
2 linphone
3 Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19
20
21 #include "sal_eXosip2.h"
22
23
24 static SalOp * sal_find_out_subscribe(Sal *sal, int sid){
25         const MSList *elem;
26         SalOp *op;
27         for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
28                 op=(SalOp*)elem->data;
29                 if (op->sid==sid) return op;
30         }
31         return NULL;
32 }
33
34 static void sal_add_out_subscribe(Sal *sal, SalOp *op){
35         sal->out_subscribes=ms_list_append(sal->out_subscribes,op);
36 }
37
38 void sal_remove_out_subscribe(Sal *sal, SalOp *op){
39         sal->out_subscribes=ms_list_remove(sal->out_subscribes,op);
40 }
41
42 static SalOp * sal_find_in_subscribe(Sal *sal, int nid){
43         const MSList *elem;
44         SalOp *op;
45         for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
46                 op=(SalOp*)elem->data;
47                 if (op->nid==nid) return op;
48         }
49         return NULL;
50 }
51
52 static SalOp * sal_find_in_subscribe_by_call_id(Sal *sal, osip_call_id_t *call_id){
53         const MSList *elem;
54         SalOp *op;
55         for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
56                 op=(SalOp*)elem->data;
57                 if (op->call_id && osip_call_id_match(op->call_id,call_id)==0)
58                         return op;
59         }
60         return NULL;
61 }
62
63 static void sal_add_in_subscribe(Sal *sal, SalOp *op, osip_message_t *subs){
64         osip_call_id_clone(subs->call_id,&op->call_id);
65         sal->in_subscribes=ms_list_append(sal->in_subscribes,op);
66 }
67
68 void sal_remove_in_subscribe(Sal *sal, SalOp *op){
69         sal->in_subscribes=ms_list_remove(sal->in_subscribes,op);
70 }
71
72 int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
73         osip_message_t *sip=NULL;
74
75         if(op->cid == -1)
76         {
77                 /* we are not currently in communication with the destination */
78                 if (from)
79                         sal_op_set_from(op,from);
80                 if (to)
81                         sal_op_set_to(op,to);
82
83                 eXosip_lock();
84                 eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op),
85                         sal_op_get_from(op),sal_op_get_route(op));
86                 osip_message_set_content_type(sip,"text/plain");
87                 osip_message_set_body(sip,msg,strlen(msg));
88                 eXosip_message_send_request(sip);
89                 eXosip_unlock();
90         }
91         else
92         {
93                 /* we are currently in communication with the destination */
94                 eXosip_lock();
95                 //First we generate an INFO message to get the current call_id and a good cseq
96                 eXosip_call_build_info(op->did,&sip);
97                 if(sip == NULL)
98                 {
99                         ms_warning("could not get a build info to send MESSAGE, maybe no previous call established ?");
100                         osip_message_free(sip);
101                         eXosip_unlock();
102                         return -1;
103                 }
104                 osip_free(sip->sip_method);
105                 //change the sip_message to be a MESSAGE ...
106                 osip_message_set_method(sip,osip_strdup("MESSAGE"));
107                 osip_message_set_content_type(sip,"text/plain");
108                 osip_message_set_body(sip,msg,strlen(msg));
109                 eXosip_message_send_request(sip);
110                 eXosip_unlock();
111         }
112         return 0;
113 }
114
115 /*presence Subscribe/notify*/
116 int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
117         osip_message_t *msg;
118         if (from)
119                 sal_op_set_from(op,from);
120         if (to)
121                 sal_op_set_to(op,to);
122         sal_exosip_fix_route(op);
123         eXosip_lock();
124         eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op),
125                 sal_op_get_route(op),"presence",600);
126         op->sid=eXosip_subscribe_send_initial_request(msg);
127         eXosip_unlock();
128         if (op->sid==-1){
129                 osip_message_free(msg);
130                 return -1;
131         }
132         sal_add_out_subscribe(op->base.root,op);
133         return 0;
134 }
135
136 int sal_unsubscribe(SalOp *op){
137         osip_message_t *msg=NULL;
138         if (op->did==-1){
139                 ms_error("cannot unsubscribe, no dialog !");
140                 return -1;
141         }
142         eXosip_lock();
143         eXosip_subscribe_build_refresh_request(op->did,&msg);
144         if (msg){
145                 osip_message_set_expires(msg,"0");
146                 eXosip_subscribe_send_refresh_request(op->did,msg);
147         }else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i",
148                 op->sid,op->did);
149         eXosip_unlock();
150         return 0;
151 }
152
153 int sal_subscribe_accept(SalOp *op){
154         osip_message_t *msg;
155         eXosip_lock();
156         eXosip_insubscription_build_answer(op->tid,202,&msg);
157         eXosip_insubscription_send_answer(op->tid,202,msg);
158         eXosip_unlock();
159         return 0;
160 }
161
162 int sal_subscribe_decline(SalOp *op){
163         eXosip_lock();
164         eXosip_insubscription_send_answer(op->tid,401,NULL);
165         eXosip_unlock();
166         return 0;
167 }
168
169 static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
170 {
171         char buf[1000];
172 #ifdef SUPPORT_MSN
173         int atom_id = 1000;
174 #endif
175         char *contact_info;
176
177         osip_contact_t *ct=NULL;
178         osip_message_get_contact(notify,0,&ct);
179         osip_contact_to_str(ct,&contact_info);
180
181 #ifdef SUPPORT_MSN
182
183   if (online_status==SalPresenceOnline)
184     {
185       sprintf(buf, "<?xml version=\"1.0\"?>\n\
186 <!DOCTYPE presence\n\
187 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
188 <presence>\n\
189 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
190 <atom id=\"%i\">\n\
191 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
192 <status status=\"open\" />\n\
193 <msnsubstatus substatus=\"online\" />\n\
194 </address>\n\
195 </atom>\n\
196 </presence>", contact_info, atom_id, contact_info);
197
198     }
199   else if (online_status==SalPresenceBusy)
200     {
201       sprintf(buf, "<?xml version=\"1.0\"?>\n\
202 <!DOCTYPE presence\n\
203 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
204 <presence>\n\
205 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
206 <atom id=\"%i\">\n\
207 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
208 <status status=\"inuse\" />\n\
209 <msnsubstatus substatus=\"busy\" />\n\
210 </address>\n\
211 </atom>\n\
212 </presence>", contact_info, atom_id, contact_info);
213
214     }
215   else if (online_status==SalPresenceBerightback)
216     {
217       sprintf(buf, "<?xml version=\"1.0\"?>\n\
218 <!DOCTYPE presence\n\
219 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
220 <presence>\n\
221 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
222 <atom id=\"%i\">\n\
223 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
224 <status status=\"inactive\" />\n\
225 <msnsubstatus substatus=\"berightback\" />\n\
226 </address>\n\
227 </atom>\n\
228 </presence>", contact_info, atom_id, contact_info);
229
230     }
231   else if (online_status==SalPresenceAway)
232     {
233       sprintf(buf, "<?xml version=\"1.0\"?>\n\
234 <!DOCTYPE presence\n\
235 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
236 <presence>\n\
237 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
238 <atom id=\"%i\">\n\
239 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
240 <status status=\"inactive\" />\n\
241 <msnsubstatus substatus=\"away\" />\n\
242 </address>\n\
243 </atom>\n\
244 </presence>", contact_info, atom_id, contact_info);
245
246     }
247   else if (online_status==SalPresenceOnthephone)
248     {
249       sprintf(buf, "<?xml version=\"1.0\"?>\n\
250 <!DOCTYPE presence\n\
251 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
252 <presence>\n\
253 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
254 <atom id=\"%i\">\n\
255 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
256 <status status=\"inuse\" />\n\
257 <msnsubstatus substatus=\"onthephone\" />\n\
258 </address>\n\
259 </atom>\n\
260 </presence>", contact_info, atom_id, contact_info);
261
262     }
263   else if (online_status==SalPresenceOuttolunch)
264     {
265       sprintf(buf, "<?xml version=\"1.0\"?>\n\
266 <!DOCTYPE presence\n\
267 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
268 <presence>\n\
269 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
270 <atom id=\"%i\">\n\
271 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
272 <status status=\"inactive\" />\n\
273 <msnsubstatus substatus=\"outtolunch\" />\n\
274 </address>\n\
275 </atom>\n\
276 </presence>", contact_info, atom_id, contact_info);
277
278     }
279   else
280     {
281       sprintf(buf, "<?xml version=\"1.0\"?>\n\
282 <!DOCTYPE presence\n\
283 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
284 <presence>\n\
285 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
286 <atom id=\"%i\">\n\
287 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
288 <status status=\"inactive\" />\n\
289 <msnsubstatus substatus=\"away\" />\n\
290 </address>\n\
291 </atom>\n\
292 </presence>", contact_info, atom_id, contact_info);
293     }
294
295   osip_message_set_body(notify, buf, strlen(buf));
296   osip_message_set_content_type(notify, "application/xpidf+xml");
297 #else
298
299   if (online_status==SalPresenceOnline)
300     {
301       sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
302 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
303           entity=\"%s\">\n\
304 <tuple id=\"sg89ae\">\n\
305 <status>\n\
306 <basic>open</basic>\n\
307 </status>\n\
308 <contact priority=\"0.8\">%s</contact>\n\
309 <note>online</note>\n\
310 </tuple>\n\
311 </presence>",
312               contact_info, contact_info);
313     }
314   else if (online_status==SalPresenceBusy)
315     {
316       sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
317 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
318           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
319           entity=\"%s\">\n\
320 <tuple id=\"sg89ae\">\n\
321 <status>\n\
322 <basic>open</basic>\n\
323 <es:activities>\n\
324   <es:activity>busy</es:activity>\n\
325 </es:activities>\n\
326 </status>\n\
327 <contact priority=\"0.8\">%s</contact>\n\
328 <note>busy</note>\n\
329 </tuple>\n\
330 </presence>",
331               contact_info, contact_info);
332     }
333   else if (online_status==SalPresenceBerightback)
334     {
335       sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
336 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
337           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
338           entity=\"%s\">\n\
339 <tuple id=\"sg89ae\">\n\
340 <status>\n\
341 <basic>open</basic>\n\
342 <es:activities>\n\
343   <es:activity>in-transit</es:activity>\n\
344 </es:activities>\n\
345 </status>\n\
346 <contact priority=\"0.8\">%s</contact>\n\
347 <note>be right back</note>\n\
348 </tuple>\n\
349 </presence>",
350               contact_info, contact_info);
351     }
352   else if (online_status==SalPresenceAway)
353     {
354       sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
355 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
356           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
357           entity=\"%s\">\n\
358 <tuple id=\"sg89ae\">\n\
359 <status>\n\
360 <basic>open</basic>\n\
361 <es:activities>\n\
362   <es:activity>away</es:activity>\n\
363 </es:activities>\n\
364 </status>\n\
365 <contact priority=\"0.8\">%s</contact>\n\
366 <note>away</note>\n\
367 </tuple>\n\
368 </presence>",
369               contact_info, contact_info);
370     }
371   else if (online_status==SalPresenceOnthephone)
372     {
373       sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
374 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
375           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
376           entity=\"%s\">\n\
377 <tuple id=\"sg89ae\">\n\
378 <status>\n\
379 <basic>open</basic>\n\
380 <es:activities>\n\
381   <es:activity>on-the-phone</es:activity>\n\
382 </es:activities>\n\
383 </status>\n\
384 <contact priority=\"0.8\">%s</contact>\n\
385 <note>on the phone</note>\n\
386 </tuple>\n\
387 </presence>",
388               contact_info, contact_info);
389     }
390   else if (online_status==SalPresenceOuttolunch)
391     {
392       sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
393 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
394           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
395           entity=\"%s\">\n\
396 <tuple id=\"sg89ae\">\n\
397 <status>\n\
398 <basic>open</basic>\n\
399 <es:activities>\n\
400   <es:activity>meal</es:activity>\n\
401 </es:activities>\n\
402 </status>\n\
403 <contact priority=\"0.8\">%s</contact>\n\
404 <note>out to lunch</note>\n\
405 </tuple>\n\
406 </presence>",
407               contact_info, contact_info);
408     }
409   else
410     {
411       /* */
412       sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
413 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
414 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
415 entity=\"%s\">\n%s",
416               contact_info,
417 "<tuple id=\"sg89ae\">\n\
418 <status>\n\
419 <basic>closed</basic>\n\
420 <es:activities>\n\
421   <es:activity>permanent-absence</es:activity>\n\
422 </es:activities>\n\
423 </status>\n\
424 </tuple>\n\
425 \n</presence>\n");
426     }
427   osip_message_set_body(notify, buf, strlen(buf));
428   osip_message_set_content_type(notify, "application/pidf+xml");
429
430 #endif
431         osip_free(contact_info);
432 }
433
434
435 int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
436         osip_message_t *msg;
437         eXosip_ss_t ss=EXOSIP_SUBCRSTATE_ACTIVE;
438         if (op->nid==-1){
439                 ms_warning("Cannot notify, subscription was closed.");
440                 return -1;
441         }
442         
443         eXosip_lock();
444         eXosip_insubscription_build_notify(op->did,ss,DEACTIVATED,&msg);
445         if (msg!=NULL){
446                 const char *identity=sal_op_get_contact(op);
447                 if (identity==NULL) identity=sal_op_get_to(op);
448                 osip_message_set_contact(msg,identity);
449                 add_presence_body(msg,status);
450                 eXosip_insubscription_send_request(op->did,msg);
451         }else ms_error("could not create notify for incoming subscription.");
452         eXosip_unlock();
453         return 0;
454 }
455
456 int sal_notify_close(SalOp *op){
457         osip_message_t *msg=NULL;
458         eXosip_lock();
459         eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg);
460         if (msg!=NULL){
461                 const char *identity=sal_op_get_contact(op);
462                 if (identity==NULL) identity=sal_op_get_to(op);
463                 osip_message_set_contact(msg,identity);
464                 add_presence_body(msg,SalPresenceOffline);
465                 eXosip_insubscription_send_request(op->did,msg);
466         }else ms_error("sal_notify_close(): could not create notify for incoming subscription"
467             " did=%i, nid=%i",op->did,op->nid);
468         eXosip_unlock();
469         return 0;
470 }
471
472 int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus presence_mode){
473         osip_message_t *pub;
474         int i;
475         char buf[1024];
476
477         if (presence_mode==SalPresenceOnline)
478         {
479           snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
480         <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
481                   entity=\"%s\">\n\
482         <tuple id=\"sg89ae\">\n\
483         <status>\n\
484         <basic>open</basic>\n\
485         </status>\n\
486         <contact priority=\"0.8\">%s</contact>\n\
487         <note>online</note>\n\
488         </tuple>\n\
489         </presence>",
490                    from, from);
491         }
492         else if (presence_mode==SalPresenceBusy
493            ||presence_mode==SalPresenceDonotdisturb)
494         {
495           snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
496         <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
497                   xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
498                   entity=\"%s\">\n\
499         <tuple id=\"sg89ae\">\n\
500         <status>\n\
501         <basic>open</basic>\n\
502         <es:activities>\n\
503         <es:activity>busy</es:activity>\n\
504         </es:activities>\n\
505         </status>\n\
506         <contact priority=\"0.8\">%s</contact>\n\
507         <note>busy</note>\n\
508         </tuple>\n\
509         </presence>",
510                   from, from);
511         }
512         else if (presence_mode==SalPresenceBerightback)
513         {
514                 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
515         <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
516                   xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
517                   entity=\"%s\">\n\
518         <tuple id=\"sg89ae\">\n\
519         <status>\n\
520         <basic>open</basic>\n\
521         <es:activities>\n\
522         <es:activity>in-transit</es:activity>\n\
523         </es:activities>\n\
524         </status>\n\
525         <contact priority=\"0.8\">%s</contact>\n\
526         <note>be right back</note>\n\
527         </tuple>\n\
528         </presence>",
529                   from,from);
530         }
531         else if (presence_mode==SalPresenceAway
532            ||presence_mode==SalPresenceMoved)
533         {
534                 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
535         <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
536                   xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
537                   entity=\"%s\">\n\
538         <tuple id=\"sg89ae\">\n\
539         <status>\n\
540         <basic>open</basic>\n\
541         <es:activities>\n\
542         <es:activity>away</es:activity>\n\
543         </es:activities>\n\
544         </status>\n\
545         <contact priority=\"0.8\">%s</contact>\n\
546         <note>away</note>\n\
547         </tuple>\n\
548         </presence>",
549                   from, from);
550         }
551         else if (presence_mode==SalPresenceOnthephone)
552         {
553           snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
554         <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
555                   xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
556                   entity=\"%s\">\n\
557         <tuple id=\"sg89ae\">\n\
558         <status>\n\
559         <basic>open</basic>\n\
560         <es:activities>\n\
561         <es:activity>on-the-phone</es:activity>\n\
562         </es:activities>\n\
563         </status>\n\
564         <contact priority=\"0.8\">%s</contact>\n\
565         <note>on the phone</note>\n\
566         </tuple>\n\
567         </presence>",
568                   from, from);
569         }
570         else if (presence_mode==SalPresenceOuttolunch)
571         {
572           snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
573         <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
574                   xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
575                   entity=\"%s\">\n\
576         <tuple id=\"sg89ae\">\n\
577         <status>\n\
578         <basic>open</basic>\n\
579         <es:activities>\n\
580         <es:activity>meal</es:activity>\n\
581         </es:activities>\n\
582         </status>\n\
583         <contact priority=\"0.8\">%s</contact>\n\
584         <note>out to lunch</note>\n\
585         </tuple>\n\
586         </presence>",
587                   from, from);
588         }
589         else{ 
590           /* offline */
591           snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
592         <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
593         xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
594         entity=\"%s\">\n%s",
595                   from,
596         "<tuple id=\"sg89ae\">\n\
597         <status>\n\
598         <basic>closed</basic>\n\
599         <es:activities>\n\
600         <es:activity>permanent-absence</e:activity>\n\
601         </es:activities>\n\
602         </status>\n\
603         </tuple>\n\
604         \n</presence>\n");
605         }
606
607         i = eXosip_build_publish(&pub,from, to, NULL, "presence", "1800", "application/pidf+xml", buf);
608         if (i<0){
609                 ms_warning("Failed to build publish request.");
610                 return -1;
611         }
612
613         eXosip_lock();
614         i = eXosip_publish(pub, to); /* should update the sip-if-match parameter
615                                     from sip-etag  from last 200ok of PUBLISH */
616         eXosip_unlock();
617         if (i<0){
618           ms_message("Failed to send publish request.");
619           return -1;
620         }
621         return 0;
622 }
623
624 static void _sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){        
625         SalOp *op=sal_op_new(sal);
626         char *tmp;
627         op->did=ev->did;
628         op->tid=ev->tid;
629         op->nid=ev->nid;
630         osip_from_to_str(ev->request->from,&tmp);
631         sal_op_set_from(op,tmp);
632         ms_free(tmp);
633         osip_from_to_str(ev->request->to,&tmp);
634         sal_op_set_to(op,tmp);
635         ms_free(tmp);
636         sal_add_in_subscribe(sal,op,ev->request);
637         sal->callbacks.subscribe_received(op,sal_op_get_from(op));
638 }
639
640 void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){        
641         /*workaround a bug in eXosip: incoming SUBSCRIBES within dialog with expires: 0 are
642          recognized as new incoming subscribes*/
643         SalOp *op=sal_find_in_subscribe_by_call_id(sal,ev->request->call_id);
644         if (op){
645                 osip_header_t *h;
646                 osip_message_header_get_byname(ev->request,"expires",0,&h);
647                 if (h && h->hvalue && atoi(h->hvalue)==0){
648                         ms_warning("This susbscribe is not a new one but terminates an old one.");
649                         ev->did=op->did;
650                         ev->nid=op->nid;
651                         sal_exosip_subscription_closed(sal,ev);
652                 }else {
653                         osip_message_t *msg=NULL;
654                         ms_warning("Probably a refresh subscribe");
655                         eXosip_lock();
656                         eXosip_insubscription_build_answer(ev->tid,202,&msg);
657                         eXosip_insubscription_send_answer(ev->tid,202,msg);
658                         eXosip_unlock();
659                 }
660         }else _sal_exosip_subscription_recv(sal,ev);
661 }
662
663 void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
664         SalOp *op=sal_find_out_subscribe(sal,ev->sid);
665         char *tmp;
666         osip_from_t *from=NULL;
667         osip_body_t *body=NULL;
668         SalPresenceStatus estatus=SalPresenceOffline;
669         
670         ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid);
671
672         if (op==NULL){
673                 ms_error("No operation related to this notify !");
674                 return;
675         }
676         if (ev->request==NULL) return;
677
678         from=ev->request->from;
679         osip_message_get_body(ev->request,0,&body);
680         if (body==NULL){
681                 ms_error("No body in NOTIFY");
682                 return;
683         }
684         osip_from_to_str(from,&tmp);
685         if (strstr(body->body,"pending")!=NULL){
686                 estatus=SalPresenceOffline;
687         }else if (strstr(body->body,"busy")!=NULL){
688                 estatus=SalPresenceBusy;
689         }else if (strstr(body->body,"berightback")!=NULL
690                         || strstr(body->body,"in-transit")!=NULL ){
691                 estatus=SalPresenceBerightback;
692         }else if (strstr(body->body,"away")!=NULL){
693                 estatus=SalPresenceAway;
694         }else if (strstr(body->body,"onthephone")!=NULL
695                 || strstr(body->body,"on-the-phone")!=NULL){
696                 estatus=SalPresenceOnthephone;
697         }else if (strstr(body->body,"outtolunch")!=NULL
698                         || strstr(body->body,"meal")!=NULL){
699                 estatus=SalPresenceOuttolunch;
700         }else if (strstr(body->body,"closed")!=NULL){
701                 estatus=SalPresenceOffline;
702         }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) {
703                 estatus=SalPresenceOnline;
704         }else{
705                 estatus=SalPresenceOffline;
706         }
707         ms_message("We are notified that %s has online status %i",tmp,estatus);
708         if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) {
709                 sal_remove_out_subscribe(sal,op);
710                 op->sid=-1;
711                 op->did=-1;
712                 ms_message("And outgoing subscription terminated by remote.");
713         }
714         sal->callbacks.notify(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL);
715         osip_free(tmp);
716 }
717
718 void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){
719         SalOp *op=sal_find_out_subscribe(sal,ev->sid);
720         if (op==NULL){
721                 ms_error("Subscription answered but no associated op !");
722                 return;
723         }
724         op->did=ev->did;
725 }
726
727 void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev){
728         SalOp *op=sal_find_in_subscribe(sal,ev->nid);
729         char *tmp;
730         if (op==NULL){
731                 ms_error("Incoming subscription closed but no associated op !");
732                 return;
733         }
734         
735         
736         sal_remove_in_subscribe(sal,op);
737         op->nid=-1;
738         op->did=-1;
739         if (ev->request){
740                 osip_from_to_str(ev->request->from,&tmp);
741                 sal->callbacks.subscribe_closed(op,tmp);
742                 osip_free(tmp);
743         }
744 }
745
746 void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){
747         SalOp *op=sal_find_out_subscribe(sal,ev->sid);
748         if (op==NULL){
749                 ms_error("Subscription closed but no associated op !");
750                 return;
751         }
752         sal_remove_out_subscribe(sal,op);
753         op->sid=-1;
754         op->did=-1;
755         sal->callbacks.notify(op,SalSubscribeTerminated, SalPresenceOffline,NULL);
756 }
757
758