]> sjero.net Git - linphone/blob - coreapi/sal_eXosip2_presence.c
Merge branch 'master' into dev_sal
[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
24 static SalOp * sal_find_out_subscribe(Sal *sal, int sid){
25         const MSList *elem;
26         SalOp *op;
27         for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
28                 op=(SalOp*)elem->data;
29                 if (op->sid==sid) return op;
30         }
31         return NULL;
32 }
33
34 static void sal_add_out_subscribe(Sal *sal, SalOp *op){
35         sal->out_subscribes=ms_list_append(sal->out_subscribes,op);
36 }
37
38 static void sal_remove_out_subscribe(Sal *sal, int sid){
39         MSList *elem;
40         SalOp *op;
41         for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){
42                 op=(SalOp*)elem->data;
43                 if (op->sid==sid) {
44                         sal->out_subscribes=ms_list_remove_link(sal->out_subscribes,elem);
45                         return;
46                 }
47         }
48 }
49
50 static SalOp * sal_find_in_subscribe(Sal *sal, int nid){
51         const MSList *elem;
52         SalOp *op;
53         for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
54                 op=(SalOp*)elem->data;
55                 if (op->nid==nid) return op;
56         }
57         return NULL;
58 }
59
60 static void sal_add_in_subscribe(Sal *sal, SalOp *op){
61         sal->in_subscribes=ms_list_append(sal->in_subscribes,op);
62 }
63
64 static void sal_remove_in_subscribe(Sal *sal, int nid){
65         MSList *elem;
66         SalOp *op;
67         for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){
68                 op=(SalOp*)elem->data;
69                 if (op->nid==nid) {
70                         sal->in_subscribes=ms_list_remove_link(sal->in_subscribes,elem);
71                         return;
72                 }
73         }
74 }
75
76 int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg){
77         osip_message_t *sip=NULL;
78         if (from)
79                 sal_op_set_from(op,from);
80         if (to)
81                 sal_op_set_to(op,to);
82
83         eXosip_lock();
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);
89         eXosip_unlock();
90         return 0;
91 }
92
93 /*presence Subscribe/notify*/
94 int sal_subscribe_presence(SalOp *op, const char *from, const char *to){
95         osip_message_t *msg;
96         if (from)
97                 sal_op_set_from(op,from);
98         if (to)
99                 sal_op_set_to(op,to);
100         eXosip_lock();
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);
104         eXosip_unlock();
105         if (op->sid==-1){
106                 osip_message_free(msg);
107                 return -1;
108         }
109         sal_add_out_subscribe(op->base.root,op);
110         return 0;
111 }
112
113 int sal_unsubscribe(SalOp *op){
114         osip_message_t *msg=NULL;
115         if (op->did==-1){
116                 ms_error("cannot unsubscribe, no dialog !");
117                 return -1;
118         }
119         eXosip_lock();
120         eXosip_subscribe_build_refresh_request(op->did,&msg);
121         if (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 !");
125         eXosip_unlock();
126         return 0;
127 }
128
129 int sal_subscribe_accept(SalOp *op){
130         osip_message_t *msg;
131         eXosip_lock();
132         eXosip_insubscription_build_answer(op->tid,202,&msg);
133         eXosip_insubscription_send_answer(op->tid,202,msg);
134         eXosip_unlock();
135         return 0;
136 }
137
138 int sal_subscribe_decline(SalOp *op){
139         eXosip_lock();
140         eXosip_insubscription_send_answer(op->tid,401,NULL);
141         eXosip_unlock();
142         return 0;
143 }
144
145 static eXosip_ss_status_t sal_presence_to_exosip(SalPresenceStatus s){
146         switch(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:
165                 default:
166                         return EXOSIP_NOTIFY_AWAY;
167         }
168 }
169
170 static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status)
171 {
172         char buf[1000];
173 #ifdef SUPPORT_MSN
174         int atom_id = 1000;
175 #endif
176         char *contact_info;
177
178         osip_contact_t *ct=NULL;
179         osip_message_get_contact(notify,0,&ct);
180         osip_contact_to_str(ct,&contact_info);
181
182 #ifdef SUPPORT_MSN
183
184   if (online_status==SalPresenceOnline)
185     {
186       sprintf(buf, "<?xml version=\"1.0\"?>\n\
187 <!DOCTYPE presence\n\
188 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
189 <presence>\n\
190 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
191 <atom id=\"%i\">\n\
192 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
193 <status status=\"open\" />\n\
194 <msnsubstatus substatus=\"online\" />\n\
195 </address>\n\
196 </atom>\n\
197 </presence>", contact_info, atom_id, contact_info);
198
199     }
200   else if (online_status==SalPresenceBusy)
201     {
202       sprintf(buf, "<?xml version=\"1.0\"?>\n\
203 <!DOCTYPE presence\n\
204 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
205 <presence>\n\
206 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
207 <atom id=\"%i\">\n\
208 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
209 <status status=\"inuse\" />\n\
210 <msnsubstatus substatus=\"busy\" />\n\
211 </address>\n\
212 </atom>\n\
213 </presence>", contact_info, atom_id, contact_info);
214
215     }
216   else if (online_status==SalPresenceBerightback)
217     {
218       sprintf(buf, "<?xml version=\"1.0\"?>\n\
219 <!DOCTYPE presence\n\
220 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
221 <presence>\n\
222 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
223 <atom id=\"%i\">\n\
224 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
225 <status status=\"inactive\" />\n\
226 <msnsubstatus substatus=\"berightback\" />\n\
227 </address>\n\
228 </atom>\n\
229 </presence>", contact_info, atom_id, contact_info);
230
231     }
232   else if (online_status==SalPresenceAway)
233     {
234       sprintf(buf, "<?xml version=\"1.0\"?>\n\
235 <!DOCTYPE presence\n\
236 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
237 <presence>\n\
238 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
239 <atom id=\"%i\">\n\
240 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
241 <status status=\"inactive\" />\n\
242 <msnsubstatus substatus=\"away\" />\n\
243 </address>\n\
244 </atom>\n\
245 </presence>", contact_info, atom_id, contact_info);
246
247     }
248   else if (online_status==SalPresenceOnthephone)
249     {
250       sprintf(buf, "<?xml version=\"1.0\"?>\n\
251 <!DOCTYPE presence\n\
252 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
253 <presence>\n\
254 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
255 <atom id=\"%i\">\n\
256 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
257 <status status=\"inuse\" />\n\
258 <msnsubstatus substatus=\"onthephone\" />\n\
259 </address>\n\
260 </atom>\n\
261 </presence>", contact_info, atom_id, contact_info);
262
263     }
264   else if (online_status==SalPresenceOuttolunch)
265     {
266       sprintf(buf, "<?xml version=\"1.0\"?>\n\
267 <!DOCTYPE presence\n\
268 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
269 <presence>\n\
270 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
271 <atom id=\"%i\">\n\
272 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
273 <status status=\"inactive\" />\n\
274 <msnsubstatus substatus=\"outtolunch\" />\n\
275 </address>\n\
276 </atom>\n\
277 </presence>", contact_info, atom_id, contact_info);
278
279     }
280   else
281     {
282       sprintf(buf, "<?xml version=\"1.0\"?>\n\
283 <!DOCTYPE presence\n\
284 PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n\
285 <presence>\n\
286 <presentity uri=\"%s;method=SUBSCRIBE\" />\n\
287 <atom id=\"%i\">\n\
288 <address uri=\"%s;user=ip\" priority=\"0.800000\">\n\
289 <status status=\"inactive\" />\n\
290 <msnsubstatus substatus=\"away\" />\n\
291 </address>\n\
292 </atom>\n\
293 </presence>", contact_info, atom_id, contact_info);
294     }
295
296   osip_message_set_body(notify, buf, strlen(buf));
297   osip_message_set_content_type(notify, "application/xpidf+xml");
298 #else
299
300   if (online_status==SalPresenceOnline)
301     {
302       sprintf(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
303 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
304           entity=\"%s\">\n\
305 <tuple id=\"sg89ae\">\n\
306 <status>\n\
307 <basic>open</basic>\n\
308 </status>\n\
309 <contact priority=\"0.8\">%s</contact>\n\
310 <note>online</note>\n\
311 </tuple>\n\
312 </presence>",
313               contact_info, contact_info);
314     }
315   else if (online_status==SalPresenceBusy)
316     {
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\
320           entity=\"%s\">\n\
321 <tuple id=\"sg89ae\">\n\
322 <status>\n\
323 <basic>open</basic>\n\
324 <es:activities>\n\
325   <es:activity>busy</es:activity>\n\
326 </es:activities>\n\
327 </status>\n\
328 <contact priority=\"0.8\">%s</contact>\n\
329 <note>busy</note>\n\
330 </tuple>\n\
331 </presence>",
332               contact_info, contact_info);
333     }
334   else if (online_status==SalPresenceBerightback)
335     {
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\
339           entity=\"%s\">\n\
340 <tuple id=\"sg89ae\">\n\
341 <status>\n\
342 <basic>open</basic>\n\
343 <es:activities>\n\
344   <es:activity>in-transit</es:activity>\n\
345 </es:activities>\n\
346 </status>\n\
347 <contact priority=\"0.8\">%s</contact>\n\
348 <note>be right back</note>\n\
349 </tuple>\n\
350 </presence>",
351               contact_info, contact_info);
352     }
353   else if (online_status==SalPresenceAway)
354     {
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\
358           entity=\"%s\">\n\
359 <tuple id=\"sg89ae\">\n\
360 <status>\n\
361 <basic>open</basic>\n\
362 <es:activities>\n\
363   <es:activity>away</es:activity>\n\
364 </es:activities>\n\
365 </status>\n\
366 <contact priority=\"0.8\">%s</contact>\n\
367 <note>away</note>\n\
368 </tuple>\n\
369 </presence>",
370               contact_info, contact_info);
371     }
372   else if (online_status==SalPresenceOnthephone)
373     {
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\
377           entity=\"%s\">\n\
378 <tuple id=\"sg89ae\">\n\
379 <status>\n\
380 <basic>open</basic>\n\
381 <es:activities>\n\
382   <es:activity>on-the-phone</es:activity>\n\
383 </es:activities>\n\
384 </status>\n\
385 <contact priority=\"0.8\">%s</contact>\n\
386 <note>on the phone</note>\n\
387 </tuple>\n\
388 </presence>",
389               contact_info, contact_info);
390     }
391   else if (online_status==SalPresenceOuttolunch)
392     {
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\
396           entity=\"%s\">\n\
397 <tuple id=\"sg89ae\">\n\
398 <status>\n\
399 <basic>open</basic>\n\
400 <es:activities>\n\
401   <es:activity>meal</es:activity>\n\
402 </es:activities>\n\
403 </status>\n\
404 <contact priority=\"0.8\">%s</contact>\n\
405 <note>out to lunch</note>\n\
406 </tuple>\n\
407 </presence>",
408               contact_info, contact_info);
409     }
410   else
411     {
412       /* */
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\
416 entity=\"%s\">\n%s",
417               contact_info,
418 "<tuple id=\"sg89ae\">\n\
419 <status>\n\
420 <basic>closed</basic>\n\
421 <es:activities>\n\
422   <es:activity>permanent-absence</es:activity>\n\
423 </es:activities>\n\
424 </status>\n\
425 </tuple>\n\
426 \n</presence>\n");
427     }
428   osip_message_set_body(notify, buf, strlen(buf));
429   osip_message_set_content_type(notify, "application/pidf+xml");
430
431 #endif
432         osip_free(contact_info);
433 }
434
435
436 int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){
437         osip_message_t *msg;
438         eXosip_ss_status_t ss;
439         if (op->nid==-1){
440                 ms_warning("Cannot notify, subscription was closed.");
441                 return -1;
442         }
443         ss=sal_presence_to_exosip(status);
444         eXosip_lock();
445         eXosip_insubscription_build_notify(op->did,ss,0,&msg);
446         if (msg!=NULL){
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.");
453         eXosip_unlock();
454         return 0;
455 }
456
457 void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){
458         SalOp *op=sal_op_new(sal);
459         char *tmp;
460         op->did=ev->did;
461         op->tid=ev->tid;
462         op->nid=ev->nid;
463         osip_from_to_str(ev->request->from,&tmp);
464         sal_op_set_from(op,tmp);
465         ms_free(tmp);
466         osip_from_to_str(ev->request->to,&tmp);
467         sal_op_set_to(op,tmp);
468         ms_free(tmp);
469         sal_add_in_subscribe(sal,op);
470         sal->callbacks.subscribe_received(op,sal_op_get_from(op));
471 }
472
473 void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){
474         SalOp *op=sal_find_out_subscribe(sal,ev->sid);
475         char *tmp;
476         osip_from_t *from=NULL;
477         osip_body_t *body=NULL;
478         SalPresenceStatus estatus=SalPresenceOffline;
479         
480         ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid);
481
482         if (op==NULL){
483                 ms_error("No operation related to this notify !");
484                 return;
485         }
486         if (ev->request==NULL) return;
487
488         from=ev->request->from;
489         osip_message_get_body(ev->request,0,&body);
490         if (body==NULL){
491                 ms_error("No body in NOTIFY");
492                 return;
493         }
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;
514         }else{
515                 estatus=SalPresenceOffline;
516         }
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);
520                 op->sid=-1;
521                 op->did=-1;
522                 ms_message("And outgoing subscription terminated by remote.");
523         }
524         sal->callbacks.presence_changed(op,estatus,NULL);
525         osip_free(tmp);
526 }
527
528 void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){
529         SalOp *op=sal_find_out_subscribe(sal,ev->sid);
530         if (op==NULL){
531                 ms_error("Subscription answered but no associated op !");
532                 return;
533         }
534         op->did=ev->did;
535 }
536
537 void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){
538         SalOp *op=sal_find_in_subscribe(sal,ev->sid);
539         if (op==NULL){
540                 ms_error("Subscription closed but no associated op !");
541                 return;
542         }
543         sal_remove_in_subscribe(sal,op->nid);
544         op->nid=-1;
545         op->did=0;
546 }
547