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