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