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