]> sjero.net Git - linphone/blob - coreapi/sal_eXosip2_presence.c
fix unauthicated notifies
[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 typedef enum {
24         PIDF = 0,
25         RFCxxxx = 1,
26         MSOLDPRES = 2
27 } presence_type_t;
28
29 /*
30  * REVISIT: this static variable forces every dialog to use the same presence description type depending 
31  * on what is received on a single dialog...
32  */
33 static presence_type_t presence_style = PIDF;
34
35 SalOp * sal_find_out_subscribe(Sal *sal, int sid){
36         const MSList *elem;
37         SalOp *op;
38         for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
39                 op=(SalOp*)elem->data;
40                 if (op->sid==sid) return op;
41         }
42         return NULL;
43 }
44
45 static void sal_add_out_subscribe(Sal *sal, SalOp *op){
46         sal->out_subscribes=ms_list_append(sal->out_subscribes,op);
47 }
48
49 void sal_remove_out_subscribe(Sal *sal, SalOp *op){
50         sal->out_subscribes=ms_list_remove(sal->out_subscribes,op);
51 }
52
53 SalOp * sal_find_in_subscribe(Sal *sal, int nid){
54         const MSList *elem;
55         SalOp *op;
56         for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
57                 op=(SalOp*)elem->data;
58                 if (op->nid==nid) return op;
59         }
60         return NULL;
61 }
62
63 static SalOp * sal_find_in_subscribe_by_call_id(Sal *sal, osip_call_id_t *call_id){
64         const MSList *elem;
65         SalOp *op;
66         for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
67                 op=(SalOp*)elem->data;
68                 if (op->call_id && osip_call_id_match(op->call_id,call_id)==0)
69                         return op;
70         }
71         return NULL;
72 }
73
74 static void sal_add_in_subscribe(Sal *sal, SalOp *op, osip_message_t *subs){
75         osip_call_id_clone(subs->call_id,&op->call_id);
76         sal->in_subscribes=ms_list_append(sal->in_subscribes,op);
77 }
78
79 void sal_remove_in_subscribe(Sal *sal, SalOp *op){
80         sal->in_subscribes=ms_list_remove(sal->in_subscribes,op);
81 }
82
83 int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
84         osip_message_t *sip=NULL;
85
86         if(op->cid == -1)
87         {
88                 /* we are not currently in communication with the destination */
89                 if (from)
90                         sal_op_set_from(op,from);
91                 if (to)
92                         sal_op_set_to(op,to);
93
94                 eXosip_lock();
95                 eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op),
96                         sal_op_get_from(op),sal_op_get_route(op));
97                 if (sip!=NULL){
98                         osip_message_set_content_type(sip,"text/plain");
99                         osip_message_set_body(sip,msg,strlen(msg));
100                         sal_add_other(op->base.root,op,sip);
101                         eXosip_message_send_request(sip);
102                 }else{
103                         ms_error("Could not build MESSAGE request !");
104                 }
105                 eXosip_unlock();
106         }
107         else
108         {
109                 /* we are currently in communication with the destination */
110                 eXosip_lock();
111                 //First we generate an INFO message to get the current call_id and a good cseq
112                 eXosip_call_build_request(op->did,"MESSAGE",&sip);
113                 if(sip == NULL)
114                 {
115                         ms_warning("could not get a build info to send MESSAGE, maybe no previous call established ?");
116                         eXosip_unlock();
117                         return -1;
118                 }
119                 osip_message_set_content_type(sip,"text/plain");
120                 osip_message_set_body(sip,msg,strlen(msg));
121                 eXosip_call_send_request(op->did,sip);
122                 eXosip_unlock();
123         }
124         return 0;
125 }
126
127 /*presence Subscribe/notify*/
128 int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
129         osip_message_t *msg;
130         if (from)
131                 sal_op_set_from(op,from);
132         if (to)
133                 sal_op_set_to(op,to);
134         sal_exosip_fix_route(op);
135         eXosip_lock();
136         eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op),
137                 sal_op_get_route(op),"presence",600);
138         if (op->base.contact){
139                 _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
140                 osip_message_set_contact(msg,op->base.contact);
141         }
142         op->sid=eXosip_subscribe_send_initial_request(msg);
143         eXosip_unlock();
144         if (op->sid==-1){
145                 osip_message_free(msg);
146                 return -1;
147         }
148         sal_add_out_subscribe(op->base.root,op);
149         return 0;
150 }
151
152 int sal_unsubscribe(SalOp *op){
153         osip_message_t *msg=NULL;
154         if (op->did==-1){
155                 ms_error("cannot unsubscribe, no dialog !");
156                 return -1;
157         }
158         eXosip_lock();
159         eXosip_subscribe_build_refresh_request(op->did,&msg);
160         if (msg){
161                 osip_message_set_expires(msg,"0");
162                 eXosip_subscribe_send_refresh_request(op->did,msg);
163         }else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i",
164                 op->sid,op->did);
165         eXosip_unlock();
166         return 0;
167 }
168
169 int sal_subscribe_accept(SalOp *op){
170         osip_message_t *msg;
171         eXosip_lock();
172         eXosip_insubscription_build_answer(op->tid,202,&msg);
173         if (op->base.contact){
174                 _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
175                 osip_message_set_contact(msg,op->base.contact);
176         }
177         eXosip_insubscription_send_answer(op->tid,202,msg);
178         eXosip_unlock();
179         return 0;
180 }
181
182 int sal_subscribe_decline(SalOp *op){
183         eXosip_lock();
184         eXosip_insubscription_send_answer(op->tid,401,NULL);
185         eXosip_unlock();
186         return 0;
187 }
188
189 static void mk_presence_body (const SalPresenceStatus online_status, const char *contact_info,
190                 char *buf, size_t buflen, presence_type_t ptype) {
191   switch (ptype) {
192     case RFCxxxx: {
193           /* definition from http://msdn.microsoft.com/en-us/library/cc246202%28PROT.10%29.aspx */
194           int atom_id = 1000;
195
196           if (online_status==SalPresenceOnline)
197           {
198                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
199 <!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
200 <presence>\n\
201 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
202 <atom id=\"%i\">\n\
203 <address uri=\"%s\" priority=\"0.800000\">\n\
204 <status status=\"open\" />\n\
205 <msnsubstatus substatus=\"online\" />\n\
206 </address>\n\
207 </atom>\n\
208 </presence>", contact_info, atom_id, contact_info);
209
210           }
211           else if (online_status == SalPresenceBusy ||
212                           online_status == SalPresenceDonotdisturb)
213           {
214                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
215 <!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
216 <presence>\n\
217 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
218 <atom id=\"%i\">\n\
219 <address uri=\"%s\" priority=\"0.800000\">\n\
220 <status status=\"inuse\" />\n\
221 <msnsubstatus substatus=\"busy\" />\n\
222 </address>\n\
223 </atom>\n</presence>", contact_info, atom_id, contact_info);
224
225           }
226           else if (online_status==SalPresenceBerightback)
227           {
228                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
229 <!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
230 <presence>\n\
231 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
232 <atom id=\"%i\">\n\
233 <address uri=\"%s\" priority=\"0.800000\">\n\
234 <status status=\"open\" />\n\
235 <msnsubstatus substatus=\"berightback\" />\n\
236 </address>\n\
237 </atom>\n\
238 </presence>", contact_info, atom_id, contact_info);
239
240           }
241           else if (online_status == SalPresenceAway ||
242                           online_status == SalPresenceMoved)
243           {
244                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
245 <!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
246 <presence>\n\
247 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
248 <atom id=\"%i\">\n\
249 <address uri=\"%s\" priority=\"0.800000\">\n\
250 <status status=\"open\" />\n\
251 <msnsubstatus substatus=\"away\" />\n\
252 </address>\n\
253 </atom>\n\
254 </presence>", contact_info, atom_id, contact_info);
255
256           }
257           else if (online_status==SalPresenceOnthephone)
258           {
259                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
260 <!DOCTYPE presence 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\" 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                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
275 <!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
276 <presence>\n\
277 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
278 <atom id=\"%i\">\n\
279 <address uri=\"%s\" priority=\"0.800000\">\n\
280 <status status=\"open\" />\n\
281 <msnsubstatus substatus=\"outtolunch\" />\n\
282 </address>\n\
283 </atom>\n\
284 </presence>", contact_info, atom_id, contact_info);
285
286           }
287           else
288           {
289                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
290 <!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
291 <presence>\n\
292 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
293 <atom id=\"%i\">\n\
294 <address uri=\"%s\" priority=\"0.800000\">\n\
295 <status status=\"closed\" />\n\
296 <msnsubstatus substatus=\"away\" />\n\
297 </address>\n\
298 </atom>\n\
299 </presence>", contact_info, atom_id, contact_info);
300           }
301           break;
302     } 
303     case MSOLDPRES: {
304         /* Couldn't find schema http://schemas.microsoft.com/2002/09/sip/presence
305         *  so messages format has been taken from Communigate that can send notify
306         *  requests with this schema
307         */
308           int atom_id = 1000;
309
310           if (online_status==SalPresenceOnline)
311           {
312                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
313 <!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
314 <presence>\n\
315 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
316 <atom id=\"%i\">\n\
317 <address uri=\"%s\">\n\
318 <status status=\"open\" />\n\
319 <msnsubstatus substatus=\"online\" />\n\
320 </address>\n\
321 </atom>\n\
322 </presence>", contact_info, atom_id, contact_info);
323
324           }
325           else if (online_status == SalPresenceBusy ||
326                           online_status == SalPresenceDonotdisturb)
327           {
328                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
329 <!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
330 <presence>\n\
331 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
332 <atom id=\"%i\">\n\
333 <address uri=\"%s\">\n\
334 <status status=\"inuse\" />\n\
335 <msnsubstatus substatus=\"busy\" />\n\
336 </address>\n\
337 </atom>\n</presence>", contact_info, atom_id, contact_info);
338
339           }
340           else if (online_status==SalPresenceBerightback)
341           {
342                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
343 <!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
344 <presence>\n\
345 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
346 <atom id=\"%i\">\n\
347 <address uri=\"%s\">\n\
348 <status status=\"inactive\" />\n\
349 <msnsubstatus substatus=\"berightback\" />\n\
350 </address>\n\
351 </atom>\n\
352 </presence>", contact_info, atom_id, contact_info);
353
354           }
355           else if (online_status == SalPresenceAway ||
356                           online_status == SalPresenceMoved)
357           {
358                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
359 <!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
360 <presence>\n\
361 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
362 <atom id=\"%i\">\n\
363 <address uri=\"%s\">\n\
364 <status status=\"inactive\" />\n\
365 <msnsubstatus substatus=\"idle\" />\n\
366 </address>\n\
367 </atom>\n\
368 </presence>", contact_info, atom_id, contact_info);
369
370           }
371           else if (online_status==SalPresenceOnthephone)
372           {
373                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
374 <!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
375 <presence>\n\
376 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
377 <atom id=\"%i\">\n\
378 <address uri=\"%s\">\n\
379 <status status=\"inuse\" />\n\
380 <msnsubstatus substatus=\"onthephone\" />\n\
381 </address>\n\
382 </atom>\n\
383 </presence>", contact_info, atom_id, contact_info);
384
385           }
386           else if (online_status==SalPresenceOuttolunch)
387           {
388                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
389 <!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
390 <presence>\n\
391 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
392 <atom id=\"%i\">\n\
393 <address uri=\"%s\">\n\
394 <status status=\"inactive\" />\n\
395 <msnsubstatus substatus=\"outtolunch\" />\n\
396 </address>\n\
397 </atom>\n\
398 </presence>", contact_info, atom_id, contact_info);
399
400           }
401           else
402           {
403                   snprintf(buf, buflen, "<?xml version=\"1.0\"?>\n\
404 <!DOCTYPE presence SYSTEM \"http://schemas.microsoft.com/2002/09/sip/presence\">\n\
405 <presence>\n\
406 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
407 <atom id=\"%i\">\n\
408 <address uri=\"%s\">\n\
409 <status status=\"closed\" />\n\
410 <msnsubstatus substatus=\"offline\" />\n\
411 </address>\n\
412 </atom>\n\
413 </presence>", contact_info, atom_id, contact_info);
414           }
415         break;
416         }
417     default: { /* use pidf+xml as default format, rfc4479, rfc4480, rfc3863 */
418
419         if (online_status==SalPresenceOnline)
420         {
421                 snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
422 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
423 xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
424 xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
425 entity=\"%s\">\n\
426 <tuple id=\"sg89ae\">\n\
427 <status><basic>open</basic></status>\n\
428 <contact priority=\"0.8\">%s</contact>\n\
429 </tuple>\n\
430 </presence>",
431 contact_info, contact_info);
432         }
433         else if (online_status == SalPresenceBusy ||
434                         online_status == SalPresenceDonotdisturb)
435         {
436                 snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
437 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
438 xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
439 xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
440 entity=\"%s\">\n\
441 <tuple id=\"sg89ae\">\n\
442 <status><basic>open</basic></status>\n\
443 <contact priority=\"0.8\">%s</contact>\n\
444 </tuple>\n\
445 <dm:person id=\"sg89aep\">\n\
446 <rpid:activities><rpid:busy/></rpid:activities>\n\
447 </dm:person>\n\
448 </presence>",
449 contact_info, contact_info);
450         }
451         else if (online_status==SalPresenceBerightback)
452         {
453                 snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
454 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
455 xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
456 xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
457 entity=\"%s\">\n\
458 <tuple id=\"sg89ae\">\n\
459 <status><basic>open</basic></status>\n\
460 <contact priority=\"0.8\">%s</contact>\n\
461 </tuple>\n\
462 <dm:person id=\"sg89aep\">\n\
463 <rpid:activities><rpid:in-transit/></rpid:activities>\n\
464 </dm:person>\n\
465 </presence>",
466 contact_info, contact_info);
467         }
468         else if (online_status == SalPresenceAway ||
469                         online_status == SalPresenceMoved)
470         {
471                 snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
472 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
473 xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
474 xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
475 entity=\"%s\">\n\
476 <tuple id=\"sg89ae\">\n\
477 <status><basic>open</basic></status>\n\
478 <contact priority=\"0.8\">%s</contact>\n\
479 </tuple>\n\
480 <dm:person id=\"sg89aep\">\n\
481 <rpid:activities><rpid:away/></rpid:activities>\n\
482 </dm:person>\n\
483 </presence>",
484 contact_info, contact_info);
485         }
486         else if (online_status==SalPresenceOnthephone)
487         {
488                 snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
489 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
490 xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
491 xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
492 entity=\"%s\">\n\
493 <tuple id=\"sg89ae\">\n\
494 <status><basic>open</basic></status>\n\
495 <contact priority=\"0.8\">%s</contact>\n\
496 </tuple>\n\
497 <dm:person id=\"sg89aep\">\n\
498 <rpid:activities><rpid:on-the-phone/></rpid:activities>\n\
499 </dm:person>\n\
500 </presence>",
501 contact_info, contact_info);
502         }
503         else if (online_status==SalPresenceOuttolunch)
504         {
505                 snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
506 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
507 xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
508 xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
509 entity=\"%s\">\n\
510 <tuple id=\"7777\">\n\
511 <status><basic>open</basic></status>\n\
512 <contact priority=\"0.8\">%s</contact>\n\
513 </tuple>\n\
514 <dm:person id=\"78787878\">\n\
515 <rpid:activities><rpid:meal/></rpid:activities>\n\
516 <rpid:note>Out to lunch</rpid:note> \n\
517 </dm:person>\n\
518 </presence>",
519 contact_info, contact_info);
520         }
521         else
522         {
523                 snprintf(buf, buflen, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
524 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\" \
525 xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\" \
526 xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\" \
527 entity=\"%s\">\n\
528 <tuple id=\"sg89ae\">\n\
529 <status><basic>closed</basic></status>\n\
530 <contact priority=\"0.8\">%s</contact>\n\
531 </tuple>\n\
532 </presence>\n", contact_info, contact_info);
533         }
534         break;
535     }
536  } // switch
537
538 }
539
540 static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
541 {
542         char buf[1000];
543         char *contact_info;
544
545         osip_from_t *from=NULL;
546         from=osip_message_get_from(notify);
547         osip_uri_to_str(from->url,&contact_info);
548
549         mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style);
550
551         osip_message_set_body(notify, buf, strlen(buf));
552         osip_message_set_content_type(notify,
553                 presence_style ? "application/xpidf+xml" : "application/pidf+xml");
554
555         osip_free(contact_info);
556 }
557
558
559 int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
560         osip_message_t *msg;
561         eXosip_ss_t ss=EXOSIP_SUBCRSTATE_ACTIVE;
562         if (op->nid==-1){
563                 ms_warning("Cannot notify, subscription was closed.");
564                 return -1;
565         }
566         
567         eXosip_lock();
568         eXosip_insubscription_build_notify(op->did,ss,DEACTIVATED,&msg);
569         if (msg!=NULL){
570                 const char *identity=sal_op_get_contact(op);
571                 if (identity==NULL) identity=sal_op_get_to(op);
572                 _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
573                 osip_message_set_contact(msg,identity);
574                 add_presence_body(msg,status);
575                 eXosip_insubscription_send_request(op->did,msg);
576         }else ms_error("could not create notify for incoming subscription.");
577         eXosip_unlock();
578         return 0;
579 }
580
581 int sal_notify_close(SalOp *op){
582         osip_message_t *msg=NULL;
583         eXosip_lock();
584         eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg);
585         if (msg!=NULL){
586                 const char *identity=sal_op_get_contact(op);
587                 if (identity==NULL) identity=sal_op_get_to(op);
588                 osip_message_set_contact(msg,identity);
589                 add_presence_body(msg,SalPresenceOffline);
590                 eXosip_insubscription_send_request(op->did,msg);
591         }else ms_error("sal_notify_close(): could not create notify for incoming subscription"
592             " did=%i, nid=%i",op->did,op->nid);
593         eXosip_unlock();
594         return 0;
595 }
596
597 int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus presence_mode){
598         osip_message_t *pub;
599         int i;
600         char buf[1024];
601
602         mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style);
603
604         i = eXosip_build_publish(&pub,from, to, NULL, "presence", "300", 
605                 presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf);
606         if (i<0){
607                 ms_warning("Failed to build publish request.");
608                 return -1;
609         }
610
611         eXosip_lock();
612         i = eXosip_publish(pub, to); /* should update the sip-if-match parameter
613                                     from sip-etag  from last 200ok of PUBLISH */
614         eXosip_unlock();
615         if (i<0){
616           ms_message("Failed to send publish request.");
617           return -1;
618         }
619         sal_add_other(sal_op_get_sal(op),op,pub);
620         return 0;
621 }
622
623 static void _sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){        
624         SalOp *op=sal_op_new(sal);
625         char *tmp;
626         op->did=ev->did;
627         op->tid=ev->tid;
628         op->nid=ev->nid;
629         osip_from_to_str(ev->request->from,&tmp);
630         sal_op_set_from(op,tmp);
631         ms_free(tmp);
632         osip_from_to_str(ev->request->to,&tmp);
633         sal_op_set_to(op,tmp);
634         ms_free(tmp);
635         sal_add_in_subscribe(sal,op,ev->request);
636         sal->callbacks.subscribe_received(op,sal_op_get_from(op));
637 }
638
639 void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){        
640         /*workaround a bug in eXosip: incoming SUBSCRIBES within dialog with expires: 0 are
641          recognized as new incoming subscribes*/
642         SalOp *op=sal_find_in_subscribe_by_call_id(sal,ev->request->call_id);
643         if (op){
644                 osip_header_t *h;
645                 osip_message_header_get_byname(ev->request,"expires",0,&h);
646                 if (h && h->hvalue && atoi(h->hvalue)==0){
647                         ms_warning("This susbscribe is not a new one but terminates an old one.");
648                         ev->did=op->did;
649                         ev->nid=op->nid;
650                         sal_exosip_subscription_closed(sal,ev);
651                 }else {
652                         osip_message_t *msg=NULL;
653                         ms_warning("Probably a refresh subscribe");
654                         eXosip_lock();
655                         eXosip_insubscription_build_answer(ev->tid,202,&msg);
656                         eXosip_insubscription_send_answer(ev->tid,202,msg);
657                         eXosip_unlock();
658                 }
659         }else _sal_exosip_subscription_recv(sal,ev);
660 }
661
662 void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
663         SalOp *op=sal_find_out_subscribe(sal,ev->sid);
664         char *tmp;
665         osip_from_t *from=NULL;
666         osip_body_t *body=NULL;
667         SalPresenceStatus estatus=SalPresenceOffline;
668         
669         ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid);
670
671         if (op==NULL){
672                 ms_error("No operation related to this notify !");
673                 return;
674         }
675         if (ev->request==NULL) return;
676
677         from=ev->request->from;
678         osip_message_get_body(ev->request,0,&body);
679         if (body==NULL){
680                 ms_error("No body in NOTIFY");
681                 return;
682         }
683         osip_from_to_str(from,&tmp);
684         if (strstr(body->body,"pending")!=NULL){
685                 estatus=SalPresenceOffline;
686         }else if (strstr(body->body,"busy")!=NULL){
687                 estatus=SalPresenceBusy;
688         }else if (strstr(body->body,"berightback")!=NULL
689                         || strstr(body->body,"in-transit")!=NULL ){
690                 estatus=SalPresenceBerightback;
691         }else if (strstr(body->body,"away")!=NULL
692                         || strstr(body->body,"idle")){
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_presence(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL);
715
716         /* try to detect presence message style used by server,
717          * and switch our presence messages to servers style */
718         if (strstr (body->body, "//IETF//DTD RFCxxxx XPIDF 1.0//EN") != NULL) {
719                 presence_style = RFCxxxx;
720         } else if (strstr(body->body,"http://schemas.microsoft.com/2002/09/sip/presence")!=NULL) {
721                 presence_style = MSOLDPRES;
722         }
723         
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