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 static void sal_remove_out_subscribe(Sal *sal, int sid){
41 for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
42 op=(SalOp*)elem->data;
44 sal->out_subscribes=ms_list_remove_link(sal->out_subscribes,elem);
50 static SalOp * sal_find_in_subscribe(Sal *sal, int nid){
53 for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
54 op=(SalOp*)elem->data;
55 if (op->nid==nid) return op;
60 static void sal_add_in_subscribe(Sal *sal, SalOp *op){
61 sal->in_subscribes=ms_list_append(sal->in_subscribes,op);
64 static void sal_remove_in_subscribe(Sal *sal, int nid){
67 for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
68 op=(SalOp*)elem->data;
70 sal->in_subscribes=ms_list_remove_link(sal->in_subscribes,elem);
76 int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
77 osip_message_t *sip=NULL;
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 /*presence Subscribe/notify*/
94 int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
97 sal_op_set_from(op,from);
101 eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op),
102 sal_op_get_route(op),"presence",600);
103 op->sid=eXosip_subscribe_send_initial_request(msg);
106 osip_message_free(msg);
109 sal_add_out_subscribe(op->base.root,op);
113 int sal_unsubscribe(SalOp *op){
114 osip_message_t *msg=NULL;
116 ms_error("cannot unsubscribe, no dialog !");
120 eXosip_subscribe_build_refresh_request(op->did,&msg);
122 osip_message_set_expires(msg,"0");
123 eXosip_subscribe_send_refresh_request(op->did,msg);
124 }else ms_error("Could not build subscribe refresh request !");
129 int sal_subscribe_accept(SalOp *op){
132 eXosip_insubscription_build_answer(op->tid,202,&msg);
133 eXosip_insubscription_send_answer(op->tid,202,msg);
138 int sal_subscribe_decline(SalOp *op){
140 eXosip_insubscription_send_answer(op->tid,401,NULL);
145 static eXosip_ss_status_t sal_presence_to_exosip(SalPresenceStatus s){
147 case SalPresenceOffline:
148 return EXOSIP_NOTIFY_CLOSED;
149 case SalPresenceOnline:
150 return EXOSIP_NOTIFY_ONLINE;
151 case SalPresenceBusy:
152 return EXOSIP_NOTIFY_BUSY;
153 case SalPresenceBerightback:
154 return EXOSIP_NOTIFY_BERIGHTBACK;
155 case SalPresenceAway:
156 return EXOSIP_NOTIFY_AWAY;
157 case SalPresenceOnthephone:
158 return EXOSIP_NOTIFY_ONTHEPHONE;
159 case SalPresenceOuttolunch:
160 return EXOSIP_NOTIFY_OUTTOLUNCH;
161 case SalPresenceDonotdisturb:
162 return EXOSIP_NOTIFY_BUSY;
163 case SalPresenceMoved:
164 case SalPresenceAltService:
166 return EXOSIP_NOTIFY_AWAY;
170 static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
178 osip_contact_t *ct=NULL;
179 osip_message_get_contact(notify,0,&ct);
180 osip_contact_to_str(ct,&contact_info);
184 if (online_status==SalPresenceOnline)
186 sprintf(buf, "<?xml version=\"1.0\"?>\n\
187 <!DOCTYPE presence\n\
188 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
190 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
192 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
193 <status status=\"open\" />\n\
194 <msnsubstatus substatus=\"online\" />\n\
197 </presence>", contact_info, atom_id, contact_info);
200 else if (online_status==SalPresenceBusy)
202 sprintf(buf, "<?xml version=\"1.0\"?>\n\
203 <!DOCTYPE presence\n\
204 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
206 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
208 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
209 <status status=\"inuse\" />\n\
210 <msnsubstatus substatus=\"busy\" />\n\
213 </presence>", contact_info, atom_id, contact_info);
216 else if (online_status==SalPresenceBerightback)
218 sprintf(buf, "<?xml version=\"1.0\"?>\n\
219 <!DOCTYPE presence\n\
220 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
222 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
224 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
225 <status status=\"inactive\" />\n\
226 <msnsubstatus substatus=\"berightback\" />\n\
229 </presence>", contact_info, atom_id, contact_info);
232 else if (online_status==SalPresenceAway)
234 sprintf(buf, "<?xml version=\"1.0\"?>\n\
235 <!DOCTYPE presence\n\
236 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
238 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
240 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
241 <status status=\"inactive\" />\n\
242 <msnsubstatus substatus=\"away\" />\n\
245 </presence>", contact_info, atom_id, contact_info);
248 else if (online_status==SalPresenceOnthephone)
250 sprintf(buf, "<?xml version=\"1.0\"?>\n\
251 <!DOCTYPE presence\n\
252 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
254 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
256 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
257 <status status=\"inuse\" />\n\
258 <msnsubstatus substatus=\"onthephone\" />\n\
261 </presence>", contact_info, atom_id, contact_info);
264 else if (online_status==SalPresenceOuttolunch)
266 sprintf(buf, "<?xml version=\"1.0\"?>\n\
267 <!DOCTYPE presence\n\
268 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
270 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
272 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
273 <status status=\"inactive\" />\n\
274 <msnsubstatus substatus=\"outtolunch\" />\n\
277 </presence>", contact_info, atom_id, contact_info);
282 sprintf(buf, "<?xml version=\"1.0\"?>\n\
283 <!DOCTYPE presence\n\
284 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
286 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
288 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
289 <status status=\"inactive\" />\n\
290 <msnsubstatus substatus=\"away\" />\n\
293 </presence>", contact_info, atom_id, contact_info);
296 osip_message_set_body(notify, buf, strlen(buf));
297 osip_message_set_content_type(notify, "application/xpidf+xml");
300 if (online_status==SalPresenceOnline)
302 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
303 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
305 <tuple id=\"sg89ae\">\n\
307 <basic>open</basic>\n\
309 <contact priority=\"0.8\">%s</contact>\n\
310 <note>online</note>\n\
313 contact_info, contact_info);
315 else if (online_status==SalPresenceBusy)
317 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
318 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
319 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
321 <tuple id=\"sg89ae\">\n\
323 <basic>open</basic>\n\
325 <es:activity>busy</es:activity>\n\
328 <contact priority=\"0.8\">%s</contact>\n\
332 contact_info, contact_info);
334 else if (online_status==SalPresenceBerightback)
336 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
337 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
338 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
340 <tuple id=\"sg89ae\">\n\
342 <basic>open</basic>\n\
344 <es:activity>in-transit</es:activity>\n\
347 <contact priority=\"0.8\">%s</contact>\n\
348 <note>be right back</note>\n\
351 contact_info, contact_info);
353 else if (online_status==SalPresenceAway)
355 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
356 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
357 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
359 <tuple id=\"sg89ae\">\n\
361 <basic>open</basic>\n\
363 <es:activity>away</es:activity>\n\
366 <contact priority=\"0.8\">%s</contact>\n\
370 contact_info, contact_info);
372 else if (online_status==SalPresenceOnthephone)
374 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
375 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
376 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
378 <tuple id=\"sg89ae\">\n\
380 <basic>open</basic>\n\
382 <es:activity>on-the-phone</es:activity>\n\
385 <contact priority=\"0.8\">%s</contact>\n\
386 <note>on the phone</note>\n\
389 contact_info, contact_info);
391 else if (online_status==SalPresenceOuttolunch)
393 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
394 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
395 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
397 <tuple id=\"sg89ae\">\n\
399 <basic>open</basic>\n\
401 <es:activity>meal</es:activity>\n\
404 <contact priority=\"0.8\">%s</contact>\n\
405 <note>out to lunch</note>\n\
408 contact_info, contact_info);
413 sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
414 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
415 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
418 "<tuple id=\"sg89ae\">\n\
420 <basic>closed</basic>\n\
422 <es:activity>permanent-absence</es:activity>\n\
428 osip_message_set_body(notify, buf, strlen(buf));
429 osip_message_set_content_type(notify, "application/pidf+xml");
432 osip_free(contact_info);
436 int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
438 eXosip_ss_status_t ss;
440 ms_warning("Cannot notify, subscription was closed.");
443 ss=sal_presence_to_exosip(status);
445 eXosip_insubscription_build_notify(op->did,ss,0,&msg);
447 const char *identity=sal_op_get_contact(op);
448 if (identity==NULL) identity=sal_op_get_to(op);
449 osip_message_set_contact(msg,identity);
450 add_presence_body(msg,status);
451 eXosip_insubscription_send_request(op->did,msg);
452 }else ms_error("could not create notify for incoming subscription.");
457 void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){
458 SalOp *op=sal_op_new(sal);
463 osip_from_to_str(ev->request->from,&tmp);
464 sal_op_set_from(op,tmp);
466 osip_from_to_str(ev->request->to,&tmp);
467 sal_op_set_to(op,tmp);
469 sal_add_in_subscribe(sal,op);
470 sal->callbacks.subscribe_received(op,sal_op_get_from(op));
473 void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
474 SalOp *op=sal_find_out_subscribe(sal,ev->sid);
476 osip_from_t *from=NULL;
477 osip_body_t *body=NULL;
478 SalPresenceStatus estatus=SalPresenceOffline;
480 ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid);
483 ms_error("No operation related to this notify !");
486 if (ev->request==NULL) return;
488 from=ev->request->from;
489 osip_message_get_body(ev->request,0,&body);
491 ms_error("No body in NOTIFY");
494 osip_from_to_str(from,&tmp);
495 if (strstr(body->body,"pending")!=NULL){
496 estatus=SalPresenceOffline;
497 }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) {
498 estatus=SalPresenceOnline;
499 }else if (strstr(body->body,"busy")!=NULL){
500 estatus=SalPresenceBusy;
501 }else if (strstr(body->body,"berightback")!=NULL
502 || strstr(body->body,"in-transit")!=NULL ){
503 estatus=SalPresenceBerightback;
504 }else if (strstr(body->body,"away")!=NULL){
505 estatus=SalPresenceAway;
506 }else if (strstr(body->body,"onthephone")!=NULL
507 || strstr(body->body,"on-the-phone")!=NULL){
508 estatus=SalPresenceOnthephone;
509 }else if (strstr(body->body,"outtolunch")!=NULL
510 || strstr(body->body,"meal")!=NULL){
511 estatus=SalPresenceOuttolunch;
512 }else if (strstr(body->body,"closed")!=NULL){
513 estatus=SalPresenceOffline;
515 estatus=SalPresenceOffline;
517 ms_message("We are notified that %s has online status %i",tmp,estatus);
518 if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) {
519 sal_remove_out_subscribe(sal,op->sid);
522 ms_message("And outgoing subscription terminated by remote.");
524 sal->callbacks.presence_changed(op,estatus,NULL);
528 void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){
529 SalOp *op=sal_find_out_subscribe(sal,ev->sid);
531 ms_error("Subscription answered but no associated op !");
537 void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){
538 SalOp *op=sal_find_in_subscribe(sal,ev->sid);
540 ms_error("Subscription closed but no associated op !");
543 sal_remove_in_subscribe(sal,op->nid);