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