3 Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr)
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.
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.
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.
21 #include "sal_eXosip2.h"
24 static SalOp * sal_find_out_subscribe(Sal *sal, int sid){
27 for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
28 op=(SalOp*)elem->data;
29 if (op->sid==sid) return op;
34 static void sal_add_out_subscribe(Sal *sal, SalOp *op){
35 sal->out_subscribes=ms_list_append(sal->out_subscribes,op);
38 void sal_remove_out_subscribe(Sal *sal, SalOp *op){
39 sal->out_subscribes=ms_list_remove(sal->out_subscribes,op);
42 static SalOp * sal_find_in_subscribe(Sal *sal, int nid){
45 for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
46 op=(SalOp*)elem->data;
47 if (op->nid==nid) return op;
52 static SalOp * sal_find_in_subscribe_by_call_id(Sal *sal, osip_call_id_t *call_id){
55 for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
56 op=(SalOp*)elem->data;
57 if (op->call_id && osip_call_id_match(op->call_id,call_id)==0)
63 static void sal_add_in_subscribe(Sal *sal, SalOp *op, osip_message_t *subs){
64 osip_call_id_clone(subs->call_id,&op->call_id);
65 sal->in_subscribes=ms_list_append(sal->in_subscribes,op);
68 void sal_remove_in_subscribe(Sal *sal, SalOp *op){
69 sal->in_subscribes=ms_list_remove(sal->in_subscribes,op);
72 int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
73 osip_message_t *sip=NULL;
77 /* we are not currently in communication with the destination */
79 sal_op_set_from(op,from);
84 eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op),
85 sal_op_get_from(op),sal_op_get_route(op));
86 osip_message_set_content_type(sip,"text/plain");
87 osip_message_set_body(sip,msg,strlen(msg));
88 eXosip_message_send_request(sip);
93 /* we are currently in communication with the destination */
95 //First we generate an INFO message to get the current call_id and a good cseq
96 eXosip_call_build_info(op->did,&sip);
99 ms_warning("could not get a build info to send MESSAGE, maybe no previous call established ?");
100 osip_message_free(sip);
104 //change the sip_message to be a MESSAGE ...
105 osip_free(osip_message_get_method(sip));
106 osip_message_set_method(sip,osip_strdup("MESSAGE"));
107 osip_free(osip_cseq_get_method(osip_message_get_cseq(sip)));
108 osip_cseq_set_method(osip_message_get_cseq(sip),osip_strdup("MESSAGE"));
109 osip_message_set_content_type(sip,"text/plain");
110 osip_message_set_body(sip,msg,strlen(msg));
111 eXosip_message_send_request(sip);
117 /*presence Subscribe/notify*/
118 int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
121 sal_op_set_from(op,from);
123 sal_op_set_to(op,to);
124 sal_exosip_fix_route(op);
126 eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op),
127 sal_op_get_route(op),"presence",600);
128 op->sid=eXosip_subscribe_send_initial_request(msg);
131 osip_message_free(msg);
134 sal_add_out_subscribe(op->base.root,op);
138 int sal_unsubscribe(SalOp *op){
139 osip_message_t *msg=NULL;
141 ms_error("cannot unsubscribe, no dialog !");
145 eXosip_subscribe_build_refresh_request(op->did,&msg);
147 osip_message_set_expires(msg,"0");
148 eXosip_subscribe_send_refresh_request(op->did,msg);
149 }else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i",
155 int sal_subscribe_accept(SalOp *op){
158 eXosip_insubscription_build_answer(op->tid,202,&msg);
159 eXosip_insubscription_send_answer(op->tid,202,msg);
164 int sal_subscribe_decline(SalOp *op){
166 eXosip_insubscription_send_answer(op->tid,401,NULL);
171 static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
179 osip_from_t *from=NULL;
180 from=osip_message_get_from(notify);
181 osip_uri_to_str(from->url,&contact_info);
185 if (online_status==SalPresenceOnline)
187 sprintf(buf, "<?xml version=\"1.0\"?>\n\
188 <!DOCTYPE presence\n\
189 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
191 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
193 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
194 <status status=\"open\" />\n\
195 <msnsubstatus substatus=\"online\" />\n\
198 </presence>", contact_info, atom_id, contact_info);
201 else if (online_status==SalPresenceBusy)
203 sprintf(buf, "<?xml version=\"1.0\"?>\n\
204 <!DOCTYPE presence\n\
205 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
207 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
209 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
210 <status status=\"inuse\" />\n\
211 <msnsubstatus substatus=\"busy\" />\n\
214 </presence>", contact_info, atom_id, contact_info);
217 else if (online_status==SalPresenceBerightback)
219 sprintf(buf, "<?xml version=\"1.0\"?>\n\
220 <!DOCTYPE presence\n\
221 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
223 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
225 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
226 <status status=\"inactive\" />\n\
227 <msnsubstatus substatus=\"berightback\" />\n\
230 </presence>", contact_info, atom_id, contact_info);
233 else if (online_status==SalPresenceAway)
235 sprintf(buf, "<?xml version=\"1.0\"?>\n\
236 <!DOCTYPE presence\n\
237 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
239 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
241 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
242 <status status=\"inactive\" />\n\
243 <msnsubstatus substatus=\"away\" />\n\
246 </presence>", contact_info, atom_id, contact_info);
249 else if (online_status==SalPresenceOnthephone)
251 sprintf(buf, "<?xml version=\"1.0\"?>\n\
252 <!DOCTYPE presence\n\
253 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
255 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
257 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
258 <status status=\"inuse\" />\n\
259 <msnsubstatus substatus=\"onthephone\" />\n\
262 </presence>", contact_info, atom_id, contact_info);
265 else if (online_status==SalPresenceOuttolunch)
267 sprintf(buf, "<?xml version=\"1.0\"?>\n\
268 <!DOCTYPE presence\n\
269 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
271 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
273 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
274 <status status=\"inactive\" />\n\
275 <msnsubstatus substatus=\"outtolunch\" />\n\
278 </presence>", contact_info, atom_id, contact_info);
283 sprintf(buf, "<?xml version=\"1.0\"?>\n\
284 <!DOCTYPE presence\n\
285 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
287 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
289 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
290 <status status=\"inactive\" />\n\
291 <msnsubstatus substatus=\"away\" />\n\
294 </presence>", contact_info, atom_id, contact_info);
297 osip_message_set_body(notify, buf, strlen(buf));
298 osip_message_set_content_type(notify, "application/xpidf+xml");
301 if (online_status==SalPresenceOnline)
303 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
304 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
306 <tuple id=\"sg89ae\">\n\
308 <basic>open</basic>\n\
310 <contact priority=\"0.8\">%s</contact>\n\
311 <note>online</note>\n\
314 contact_info, contact_info);
316 else if (online_status==SalPresenceBusy)
318 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
319 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
320 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
322 <tuple id=\"sg89ae\">\n\
324 <basic>open</basic>\n\
326 <es:activity>busy</es:activity>\n\
329 <contact priority=\"0.8\">%s</contact>\n\
333 contact_info, contact_info);
335 else if (online_status==SalPresenceBerightback)
337 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
338 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
339 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
341 <tuple id=\"sg89ae\">\n\
343 <basic>open</basic>\n\
345 <es:activity>in-transit</es:activity>\n\
348 <contact priority=\"0.8\">%s</contact>\n\
349 <note>be right back</note>\n\
352 contact_info, contact_info);
354 else if (online_status==SalPresenceAway)
356 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
357 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
358 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
360 <tuple id=\"sg89ae\">\n\
362 <basic>open</basic>\n\
364 <es:activity>away</es:activity>\n\
367 <contact priority=\"0.8\">%s</contact>\n\
371 contact_info, contact_info);
373 else if (online_status==SalPresenceOnthephone)
375 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
376 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
377 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
379 <tuple id=\"sg89ae\">\n\
381 <basic>open</basic>\n\
383 <es:activity>on-the-phone</es:activity>\n\
386 <contact priority=\"0.8\">%s</contact>\n\
387 <note>on the phone</note>\n\
390 contact_info, contact_info);
392 else if (online_status==SalPresenceOuttolunch)
394 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
395 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
396 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
398 <tuple id=\"sg89ae\">\n\
400 <basic>open</basic>\n\
402 <es:activity>meal</es:activity>\n\
405 <contact priority=\"0.8\">%s</contact>\n\
406 <note>out to lunch</note>\n\
409 contact_info, contact_info);
414 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
415 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
416 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
419 "<tuple id=\"sg89ae\">\n\
421 <basic>closed</basic>\n\
423 <es:activity>permanent-absence</es:activity>\n\
429 osip_message_set_body(notify, buf, strlen(buf));
430 osip_message_set_content_type(notify, "application/pidf+xml");
433 osip_free(contact_info);
437 int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
439 eXosip_ss_t ss=EXOSIP_SUBCRSTATE_ACTIVE;
441 ms_warning("Cannot notify, subscription was closed.");
446 eXosip_insubscription_build_notify(op->did,ss,DEACTIVATED,&msg);
448 const char *identity=sal_op_get_contact(op);
449 if (identity==NULL) identity=sal_op_get_to(op);
450 osip_message_set_contact(msg,identity);
451 add_presence_body(msg,status);
452 eXosip_insubscription_send_request(op->did,msg);
453 }else ms_error("could not create notify for incoming subscription.");
458 int sal_notify_close(SalOp *op){
459 osip_message_t *msg=NULL;
461 eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg);
463 const char *identity=sal_op_get_contact(op);
464 if (identity==NULL) identity=sal_op_get_to(op);
465 osip_message_set_contact(msg,identity);
466 add_presence_body(msg,SalPresenceOffline);
467 eXosip_insubscription_send_request(op->did,msg);
468 }else ms_error("sal_notify_close(): could not create notify for incoming subscription"
469 " did=%i, nid=%i",op->did,op->nid);
474 int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus presence_mode){
479 if (presence_mode==SalPresenceOnline)
481 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
482 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
484 <tuple id=\"sg89ae\">\n\
486 <basic>open</basic>\n\
488 <contact priority=\"0.8\">%s</contact>\n\
489 <note>online</note>\n\
494 else if (presence_mode==SalPresenceBusy
495 ||presence_mode==SalPresenceDonotdisturb)
497 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
498 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
499 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
501 <tuple id=\"sg89ae\">\n\
503 <basic>open</basic>\n\
505 <es:activity>busy</es:activity>\n\
508 <contact priority=\"0.8\">%s</contact>\n\
514 else if (presence_mode==SalPresenceBerightback)
516 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
517 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
518 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
520 <tuple id=\"sg89ae\">\n\
522 <basic>open</basic>\n\
524 <es:activity>in-transit</es:activity>\n\
527 <contact priority=\"0.8\">%s</contact>\n\
528 <note>be right back</note>\n\
533 else if (presence_mode==SalPresenceAway
534 ||presence_mode==SalPresenceMoved)
536 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
537 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
538 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
540 <tuple id=\"sg89ae\">\n\
542 <basic>open</basic>\n\
544 <es:activity>away</es:activity>\n\
547 <contact priority=\"0.8\">%s</contact>\n\
553 else if (presence_mode==SalPresenceOnthephone)
555 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
556 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
557 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
559 <tuple id=\"sg89ae\">\n\
561 <basic>open</basic>\n\
563 <es:activity>on-the-phone</es:activity>\n\
566 <contact priority=\"0.8\">%s</contact>\n\
567 <note>on the phone</note>\n\
572 else if (presence_mode==SalPresenceOuttolunch)
574 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
575 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
576 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
578 <tuple id=\"sg89ae\">\n\
580 <basic>open</basic>\n\
582 <es:activity>meal</es:activity>\n\
585 <contact priority=\"0.8\">%s</contact>\n\
586 <note>out to lunch</note>\n\
593 snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
594 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
595 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
598 "<tuple id=\"sg89ae\">\n\
600 <basic>closed</basic>\n\
602 <es:activity>permanent-absence</e:activity>\n\
609 i = eXosip_build_publish(&pub,from, to, NULL, "presence", "1800", "application/pidf+xml", buf);
611 ms_warning("Failed to build publish request.");
616 i = eXosip_publish(pub, to); /* should update the sip-if-match parameter
617 from sip-etag from last 200ok of PUBLISH */
620 ms_message("Failed to send publish request.");
626 static void _sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){
627 SalOp *op=sal_op_new(sal);
632 osip_from_to_str(ev->request->from,&tmp);
633 sal_op_set_from(op,tmp);
635 osip_from_to_str(ev->request->to,&tmp);
636 sal_op_set_to(op,tmp);
638 sal_add_in_subscribe(sal,op,ev->request);
639 sal->callbacks.subscribe_received(op,sal_op_get_from(op));
642 void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){
643 /*workaround a bug in eXosip: incoming SUBSCRIBES within dialog with expires: 0 are
644 recognized as new incoming subscribes*/
645 SalOp *op=sal_find_in_subscribe_by_call_id(sal,ev->request->call_id);
648 osip_message_header_get_byname(ev->request,"expires",0,&h);
649 if (h && h->hvalue && atoi(h->hvalue)==0){
650 ms_warning("This susbscribe is not a new one but terminates an old one.");
653 sal_exosip_subscription_closed(sal,ev);
655 osip_message_t *msg=NULL;
656 ms_warning("Probably a refresh subscribe");
658 eXosip_insubscription_build_answer(ev->tid,202,&msg);
659 eXosip_insubscription_send_answer(ev->tid,202,msg);
662 }else _sal_exosip_subscription_recv(sal,ev);
665 void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
666 SalOp *op=sal_find_out_subscribe(sal,ev->sid);
668 osip_from_t *from=NULL;
669 osip_body_t *body=NULL;
670 SalPresenceStatus estatus=SalPresenceOffline;
672 ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid);
675 ms_error("No operation related to this notify !");
678 if (ev->request==NULL) return;
680 from=ev->request->from;
681 osip_message_get_body(ev->request,0,&body);
683 ms_error("No body in NOTIFY");
686 osip_from_to_str(from,&tmp);
687 if (strstr(body->body,"pending")!=NULL){
688 estatus=SalPresenceOffline;
689 }else if (strstr(body->body,"busy")!=NULL){
690 estatus=SalPresenceBusy;
691 }else if (strstr(body->body,"berightback")!=NULL
692 || strstr(body->body,"in-transit")!=NULL ){
693 estatus=SalPresenceBerightback;
694 }else if (strstr(body->body,"away")!=NULL){
695 estatus=SalPresenceAway;
696 }else if (strstr(body->body,"onthephone")!=NULL
697 || strstr(body->body,"on-the-phone")!=NULL){
698 estatus=SalPresenceOnthephone;
699 }else if (strstr(body->body,"outtolunch")!=NULL
700 || strstr(body->body,"meal")!=NULL){
701 estatus=SalPresenceOuttolunch;
702 }else if (strstr(body->body,"closed")!=NULL){
703 estatus=SalPresenceOffline;
704 }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) {
705 estatus=SalPresenceOnline;
707 estatus=SalPresenceOffline;
709 ms_message("We are notified that %s has online status %i",tmp,estatus);
710 if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) {
711 sal_remove_out_subscribe(sal,op);
714 ms_message("And outgoing subscription terminated by remote.");
716 sal->callbacks.notify_presence(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL);
720 void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){
721 SalOp *op=sal_find_out_subscribe(sal,ev->sid);
723 ms_error("Subscription answered but no associated op !");
729 void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev){
730 SalOp *op=sal_find_in_subscribe(sal,ev->nid);
733 ms_error("Incoming subscription closed but no associated op !");
738 sal_remove_in_subscribe(sal,op);
742 osip_from_to_str(ev->request->from,&tmp);
743 sal->callbacks.subscribe_closed(op,tmp);
748 void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){
749 SalOp *op=sal_find_out_subscribe(sal,ev->sid);
751 ms_error("Subscription closed but no associated op !");
754 sal_remove_out_subscribe(sal,op);
757 sal->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL);