root/trunk/src/presence.c

Revision 680, 15.2 kB (checked in by jajcus, 3 years ago)

- dates in the copyright header updated

Line 
1 /* $Id: presence.c,v 1.53 2004/04/13 17:44:07 jajcus Exp $ */
2
3 /*
4  *  (C) Copyright 2002-2006 Jacek Konieczny [jajcus(a)jajcus,net]
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License Version 2 as
8  *  published by the Free Software Foundation.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include "ggtrans.h"
21 #include <stdio.h>
22 #include "presence.h"
23 #include "jabber.h"
24 #include "jid.h"
25 #include "users.h"
26 #include "sessions.h"
27 #include "register.h"
28 #include "status.h"
29 #include "encoding.h"
30 #include "acl.h"
31 #include <time.h>
32 #include "debug.h"
33
34 int presence_send_error(struct stream_s *stream,const char *from,const char *to,
35                                 int code,const char *string){
36 xmlnode pres;
37 xmlnode error;
38 char *jid;
39 char *str;
40
41         pres=xmlnode_new_tag("presence");
42         jid=jid_my_registered();
43         if (from!=NULL)
44                 xmlnode_put_attrib(pres,"from",from);
45         else{
46                 char *jid;
47                 jid=jid_my_registered();
48                 xmlnode_put_attrib(pres,"from",jid);
49                 g_free(jid);
50         }
51         g_free(jid);
52         xmlnode_put_attrib(pres,"to",to);
53         xmlnode_put_attrib(pres,"type","error");
54         error=xmlnode_insert_tag(pres,"error");
55         if (code>0){
56                 str=g_strdup_printf("%03u",(unsigned)code);
57                 xmlnode_put_attrib(error,"code",str);
58                 g_free(str);
59         }
60         xmlnode_insert_cdata(error,string,-1);
61
62         stream_write(stream,pres);
63         xmlnode_free(pres);
64         return 0;
65 }
66
67
68 int presence_send_probe(struct stream_s *stream,const char *from,const char *to){
69 xmlnode pres;
70
71         pres=xmlnode_new_tag("presence");
72         if (from!=NULL)
73                 xmlnode_put_attrib(pres,"from",from);
74         else{
75                 char *jid;
76                 jid=jid_my_registered();
77                 xmlnode_put_attrib(pres,"from",jid);
78                 g_free(jid);
79         }
80         xmlnode_put_attrib(pres,"to",to);
81         xmlnode_put_attrib(pres,"type","probe");
82         stream_write(stream,pres);
83         xmlnode_free(pres);
84         return 0;
85 }
86
87 int presence_send_subscribe(struct stream_s *stream,const char *from,const char *to){
88 xmlnode pres;
89
90         pres=xmlnode_new_tag("presence");
91         if (from!=NULL)
92                 xmlnode_put_attrib(pres,"from",from);
93         else{
94                 char *jid;
95                 jid=jid_my_registered();
96                 xmlnode_put_attrib(pres,"from",jid);
97                 g_free(jid);
98         }
99         xmlnode_put_attrib(pres,"to",to);
100         xmlnode_put_attrib(pres,"type","subscribe");
101         stream_write(stream,pres);
102         xmlnode_free(pres);
103         return 0;
104 }
105
106 int presence_send_subscribed(struct stream_s *stream,const char *from,const char *to){
107 xmlnode pres;
108
109         pres=xmlnode_new_tag("presence");
110         if (from!=NULL)
111                 xmlnode_put_attrib(pres,"from",from);
112         else{
113                 char *jid;
114                 jid=jid_my_registered();
115                 xmlnode_put_attrib(pres,"from",jid);
116                 g_free(jid);
117         }
118         xmlnode_put_attrib(pres,"to",to);
119         xmlnode_put_attrib(pres,"type","subscribed");
120         stream_write(stream,pres);
121         xmlnode_free(pres);
122         return 0;
123 }
124
125 int presence_send_unsubscribed(struct stream_s *stream,const char *from,const char *to){
126 xmlnode pres;
127
128         pres=xmlnode_new_tag("presence");
129         if (from!=NULL)
130                 xmlnode_put_attrib(pres,"from",from);
131         else{
132                 char *jid;
133                 jid=jid_my_registered();
134                 xmlnode_put_attrib(pres,"from",jid);
135                 g_free(jid);
136         }
137         xmlnode_put_attrib(pres,"to",to);
138         xmlnode_put_attrib(pres,"type","unsubscribed");
139         stream_write(stream,pres);
140         xmlnode_free(pres);
141         return 0;
142 }
143
144 int presence_send_unsubscribe(struct stream_s *stream,const char *from,const char *to){
145 xmlnode pres;
146
147         pres=xmlnode_new_tag("presence");
148         if (from!=NULL)
149                 xmlnode_put_attrib(pres,"from",from);
150         else{
151                 char *jid;
152                 jid=jid_my_registered();
153                 xmlnode_put_attrib(pres,"from",jid);
154                 g_free(jid);
155         }
156         xmlnode_put_attrib(pres,"to",to);
157         xmlnode_put_attrib(pres,"type","unsubscribe");
158         stream_write(stream,pres);
159         xmlnode_free(pres);
160         return 0;
161 }
162
163 int presence_send(struct stream_s *stream,const char *from,
164                 const char *to,int available,const char *show,
165                 const char *status,GTime timestamp){
166 xmlnode pres;
167 xmlnode n;
168
169         pres=xmlnode_new_tag("presence");
170         if (from!=NULL)
171                 xmlnode_put_attrib(pres,"from",from);
172         else{
173                 char *jid;
174                 jid=jid_my_registered();
175                 xmlnode_put_attrib(pres,"from",jid);
176                 g_free(jid);
177         }
178         xmlnode_put_attrib(pres,"to",to);
179
180         if (available==-1) xmlnode_put_attrib(pres,"type","invisible");
181         else if (!available) xmlnode_put_attrib(pres,"type","unavailable");
182
183         if (show){
184                 n=xmlnode_insert_tag(pres,"show");
185                 xmlnode_insert_cdata(n,show,-1);
186         }
187         if (status){
188                 n=xmlnode_insert_tag(pres,"status");
189                 xmlnode_insert_cdata(n,to_utf8(status),-1);
190         }
191         if (timestamp){
192                 struct tm *t;
193                 char str[21];
194                 time_t ts=(time_t)timestamp;
195
196                 t=localtime(&ts);
197                 strftime(str,20,"%Y%m%dT%T",t);
198                 n=xmlnode_insert_tag(pres,"x");
199                 xmlnode_put_attrib(n,"xmlns","jabber:x:delay");
200                 xmlnode_put_attrib(n,"stamp",str);
201         }
202         stream_write(stream,pres);
203         xmlnode_free(pres);
204         return 0;
205 }
206
207 int presence(struct stream_s *stream,const char *from,const char *to,
208                 int available,const char *show,const char *status,int priority){
209 Session *s;
210 int r;
211 const char *resource;
212 User *u;
213
214         s=session_get_by_jid(from,available?stream:NULL,1);
215         if (!s){
216                 debug(L_("presence: No such session: %s"),from);
217                 presence_send_error(stream,NULL,from,407,_("Not logged in"));
218                 u=user_get_by_jid(from);
219                 if (u==NULL) presence_send_unsubscribed(stream,to,from);
220                 return -1;
221         }
222         resource=jid_get_resource(from);
223         r=session_set_status(s,resource,available,show,from_utf8(status),priority);
224         return 0;
225 }
226
227 int presence_subscribe(struct stream_s *stream,const char *from,const char *to){
228 User *u;
229 Session *s;
230 char *bare;
231 uin_t uin;
232 Contact *c;
233
234         u=user_get_by_jid(from);
235         if (jid_is_me(to)){
236                 debug(L_("Presence subscribe request sent to me"));
237                 if (!u) {
238                         presence_send_unsubscribed(stream,to,from);
239                         return 0;
240                 }
241                 presence_send_subscribed(stream,to,from);
242                 if (u->subscribe==SUB_UNDEFINED || u->subscribe==SUB_NONE) u->subscribe=SUB_TO;
243                 else if (u->subscribe==SUB_FROM) u->subscribe=SUB_BOTH;
244                 if (u->subscribe!=SUB_FROM && u->subscribe!=SUB_BOTH){
245                         presence_send_subscribe(stream,to,from);
246                 }
247                 user_save(u);
248                 return 0;
249         }
250         if (!u){
251                 g_warning(N_("Presence subscription from unknown user (%s)"),from);
252                 presence_send_unsubscribed(stream,to,from);
253                 return -1;
254         }
255         if (!jid_has_uin(to) || !jid_is_my(to)){
256                 g_warning(N_("Bad 'to': %s"),to);
257                 return -1;
258         }
259         s=session_get_by_jid(from,stream,0);
260         debug(L_("Subscribing %s to %s..."),from,to);
261         uin=jid_get_uin(to);
262         c=user_get_contact(u,uin,TRUE);
263         if (!c) {
264                 presence_send_error(stream,to,from,500,_("Subscription failed"));
265                 return -1;
266         }
267         if (c->subscribe==SUB_UNDEFINED || c->subscribe==SUB_NONE) c->subscribe=SUB_TO;
268         else if (c->subscribe==SUB_FROM) c->subscribe=SUB_BOTH;
269         user_save(u);
270
271         if (s) session_update_contact(s,c);     
272         debug(L_("Subscribed."));
273         presence_send_subscribed(stream,to,from);
274         bare=jid_normalized(from,FALSE);
275         if (c->subscribe!=SUB_FROM && c->subscribe!=SUB_BOTH) {
276                 presence_send_subscribe(stream,to,bare);
277         }
278         g_free(bare);
279         return 0;
280 }
281
282 int presence_subscribed(struct stream_s *stream,const char *from,const char *to){
283 User *u;
284 Session *s;
285 Contact *c;
286 uin_t uin;
287
288         u=user_get_by_jid(from);
289         if (!u){
290                 g_warning(N_("Presence subscription from unknown user (%s)"),from);
291                 presence_send_unsubscribe(stream,to,from);
292                 return -1;
293         }
294         if (jid_is_me(to)){
295                 if (u->subscribe==SUB_NONE) u->subscribe=SUB_FROM;
296                 else if (u->subscribe==SUB_UNDEFINED || u->subscribe==SUB_TO) u->subscribe=SUB_BOTH;
297                 user_save(u);
298                 debug(L_("Presence 'subscribed' sent to me"));
299                 return 0;
300         }
301         if (!jid_has_uin(to) || !jid_is_my(to)){
302                 g_warning(N_("Bad 'to': %s"),to);
303                 return -1;
304         }
305         s=session_get_by_jid(from,stream,0);
306         debug(L_("%s accepted %s's subscription..."),from,to);
307         uin=jid_get_uin(to);
308         c=user_get_contact(u,uin,TRUE);
309         if (!c) {
310                 return -1;
311         }
312         if (c->subscribe==SUB_UNDEFINED) c->subscribe=SUB_BOTH;
313         else if (c->subscribe==SUB_NONE) c->subscribe=SUB_FROM;
314         else if (c->subscribe==SUB_TO) c->subscribe=SUB_BOTH;
315         user_save(u);
316
317         if (s) session_update_contact(s,c);     
318         return 0;
319 }
320
321 int presence_unsubscribed(struct stream_s *stream,const char *from,const char *to){
322 User *u;
323 Session *s;
324 Contact *c;
325 uin_t uin;
326
327         u=user_get_by_jid(from);
328         if (!u){
329                 g_warning(N_("Presence 'unsubscribed' from unknown user (%s)"),from);
330                 return -1;
331         }
332         if (jid_is_me(to)){
333                 if (u->subscribe==SUB_FROM) u->subscribe=SUB_NONE;
334                 else if (u->subscribe==SUB_BOTH || u->subscribe==SUB_UNDEFINED) u->subscribe=SUB_TO;
335                 user_save(u);
336                 debug(L_("Presence 'unsubscribed' sent to me"));
337                 return 0;
338         }
339         if (!jid_has_uin(to) || !jid_is_my(to)){
340                 g_warning(N_("Bad 'to': %s"),to);
341                 return -1;
342         }
343         s=session_get_by_jid(from,stream,0);
344         debug(L_("%s denied/canceled %s's subscription..."),from,to);
345         uin=jid_get_uin(to);
346         c=user_get_contact(u,uin,TRUE);
347         if (!c) {
348                 return -1;
349         }
350         if (c->subscribe==SUB_FROM||c->subscribe==SUB_UNDEFINED) c->subscribe=SUB_NONE;
351         else if (c->subscribe==SUB_BOTH) c->subscribe=SUB_TO;
352         user_save(u);
353
354         if (s) session_update_contact(s,c);     
355         return 0;
356 }
357
358 int presence_unsubscribe(struct stream_s *stream,const char *from,const char *to){
359 User *u;
360 Session *s;
361 Contact *c;
362 uin_t uin;
363
364         u=user_get_by_jid(from);
365         if (!u){
366                 g_warning(N_("Presence subscription from unknown user (%s)"),from);
367                 presence_send_unsubscribed(stream,to,from);
368                 return -1;
369         }
370         if (jid_is_me(to)){
371                 debug(L_("Presence unsubscribe request sent to me"));
372                 if (u->subscribe==SUB_TO || u->subscribe==SUB_UNDEFINED) u->subscribe=SUB_NONE;
373                 else if (u->subscribe==SUB_BOTH) u->subscribe=SUB_FROM;
374                 user_save(u);
375                 return 0;
376         }
377         if (!jid_has_uin(to) || !jid_is_my(to)){
378                 g_warning(N_("Bad 'to': %s"),to);
379                 return -1;
380         }
381         s=session_get_by_jid(from,stream,0);
382         debug(L_("Unsubscribing %s from %s..."),from,to);
383        
384         uin=jid_get_uin(to);
385         c=user_get_contact(u,uin,FALSE);
386         if (!c) {
387                 presence_send_unsubscribed(stream,to,from);
388                 return -1;
389         }
390         if (c->subscribe==SUB_TO) c->subscribe=SUB_NONE;
391         else if (c->subscribe==SUB_BOTH) c->subscribe=SUB_FROM;
392         user_save(u);
393
394         if (s) session_update_contact(s,c);
395        
396         debug(L_("Unsubscribed."));
397         presence_send_unsubscribed(stream,to,from);
398         if (!GG_S_NA(c->status) && c->status!=-1){
399                 char *ujid;
400                 ujid=jid_build_full(uin);
401                 presence_send(stream,ujid,u->jid,0,NULL,"Unsubscribed",0);
402                 g_free(ujid);
403         }
404         return 0;
405 }
406
407 int presence_probe(struct stream_s *stream,const char *from,const char *to){
408 Session *s;
409 User *u;
410 Contact *c;
411 uin_t uin;
412 int status;
413 int available;
414 char *show,*stat,*jid;
415 GList *it;
416 GTime timestamp;
417
418         s=session_get_by_jid(from,NULL,0);
419         if (jid_is_me(to)){
420                 if (s){
421                         if (!s->connected){
422                                 presence_send(stream,to,from,0,NULL,"Disconnected",0);
423                         }
424                         else{
425                                 Resource *r=session_get_cur_resource(s);
426                                 if (r) presence_send(stream,NULL,s->user->jid,s->user->invisible?-1:r->available,
427                                                         r->show,r->status,0);
428                         }
429                 }
430                 else presence_send(stream,to,from,0,NULL,"Not logged in",0);
431                 return 0;
432         }
433
434         if (!jid_is_my(to)){
435                 presence_send_error(stream,to,from,404,_("Not Found"));
436                 return -1;
437         }
438
439         if (s) u=s->user;
440         else u=user_get_by_jid(from);
441
442         if (!u){
443                 presence_send_error(stream,to,from,407,_("Not registered"));
444                 presence_send_unsubscribed(stream,to,from);
445                 return -1;
446         }
447
448         uin=jid_get_uin(to);
449
450         c=user_get_contact(u,uin,TRUE);
451         if (!c) {
452                 return -1;
453         }
454
455         c->got_probe=TRUE;
456
457         if (s) session_update_contact(s,c);     
458
459         status=0;
460         stat=NULL;
461         timestamp=0;
462         for(it=u->contacts;it;it=it->next){
463                 Contact *c=(Contact *)it->data;
464
465                 if (c && c->uin==uin){
466                         status=c->status;
467                         timestamp=c->last_update;
468                         stat=c->status_desc;
469                 }
470         }
471         if (!status){
472                 presence_send_error(stream,to,from,404,_("Not Found"));
473                 return -1;
474         }
475         if (status==-1) return 0; /* Not known yet */
476
477         available=status_gg_to_jabber(status,&show,&stat);
478
479         if (available) jid=jid_build_full(uin);
480         else jid=jid_build(uin);
481        
482         presence_send(stream,jid,u->jid,available,show,stat,timestamp);
483
484         g_free(jid);
485        
486         return 0;
487 }
488
489
490 int presence_direct_available(struct stream_s *stream,const char *from,const char *to){
491 uin_t uin;
492 Contact *c;
493 Session *s;
494
495         uin=jid_get_uin(to);
496         if (uin<=0) return -1;
497
498         s=session_get_by_jid(from,NULL,0);
499         if (!s){
500                 g_warning(N_("Couldn't find session for '%s'"),from);
501                 return -1;
502         }
503
504         c=user_get_contact(s->user,uin,TRUE);
505         if (!c) return -1;
506         c->got_online=TRUE;
507         session_update_contact(s,c);
508         return 0;
509 }
510
511 int presence_direct_unavailable(struct stream_s *stream,const char *from,const char *to){
512 uin_t uin;
513 Contact *c;
514 Session *s;
515
516         uin=jid_get_uin(to);
517         if (uin<=0) return -1;
518
519         s=session_get_by_jid(from,NULL,0);
520         if (!s){
521                 g_warning(N_("Couldn't find session for '%s'"),from);
522                 return -1;
523         }
524
525         c=user_get_contact(s->user,uin,FALSE);
526         if (!c) return -1;
527         c->got_online=FALSE;
528         session_update_contact(s,c);
529         user_check_contact(s->user,c);
530         return 0;
531 }
532
533 int jabber_presence(struct stream_s *stream,xmlnode tag){
534 char *type;
535 char *from;
536 char *to;
537 xmlnode prio_n;
538 xmlnode show_n;
539 xmlnode status_n;
540 char *show,*status;
541 int priority;
542 char *tmp;
543 User *u;
544
545         type=xmlnode_get_attrib(tag,"type");
546         from=xmlnode_get_attrib(tag,"from");
547         to=xmlnode_get_attrib(tag,"to");
548
549         if (from) u=user_get_by_jid(from);
550         else u=NULL;
551         user_load_locale(u);
552
553         if (!acl_is_allowed(from,tag)){
554                 if (type && !strcmp(type,"error")){
555                         debug("Ignoring forbidden presence error");
556                         return -1;
557                 }
558                 if (!from) return -1;
559                 presence_send_error(stream,to,from,405,_("Not allowed"));
560                 return -1;
561         }
562
563         show_n=xmlnode_get_tag(tag,"show");
564         if (show_n) show=xmlnode_get_data(show_n);
565         else show=NULL;
566
567         status_n=xmlnode_get_tag(tag,"status");
568         if (status_n) status=xmlnode_get_data(status_n);
569         else status=NULL;
570
571         prio_n=xmlnode_get_tag(tag,"priority");
572         if (prio_n){
573                 tmp=xmlnode_get_data(prio_n);
574                 if (tmp) priority=atoi(tmp);
575                 else priority=-1;
576         }
577         else priority=-1;
578
579         if (!type) type="available";
580
581         if (!from || !to){
582                 if (strcmp(type,"error"))
583                         presence_send_error(stream,to,from,406,_("Not Acceptable"));
584                 g_warning(N_("Bad <presence/>: %s"),xmlnode2str(tag));
585                 return -1;
586         }
587
588         if (!jid_is_my(to)){
589                 if (strcmp(type,"error"))
590                         presence_send_error(stream,to,from,406,_("Not Acceptable"));
591                 g_warning(N_("Wrong 'to' in %s"),xmlnode2str(tag));
592                 return -1;
593         }
594
595         if (!strcmp(type,"available")){
596                 if (jid_has_uin(to))
597                         return presence_direct_available(stream,from,to);
598                 else
599                         return presence(stream,from,to,1,show,status,priority);
600         }
601         else if (!strcmp(type,"unavailable")){
602                 if (jid_has_uin(to))
603                         return presence_direct_unavailable(stream,from,to);
604                 else
605                         return presence(stream,from,to,0,show,status,priority);
606         }
607         if (!strcmp(type,"invisible")){
608                 if (jid_has_uin(to))
609                         return presence_direct_unavailable(stream,from,to);
610                 else
611                         return presence(stream,from,to,-1,show,status,priority);
612         }
613         else if (!strcmp(type,"subscribe"))
614                 return presence_subscribe(stream,from,to);
615         else if (!strcmp(type,"unsubscribe"))
616                 return presence_unsubscribe(stream,from,to);
617         else if (!strcmp(type,"subscribed"))
618                 return presence_subscribed(stream,from,to);
619         else if (!strcmp(type,"unsubscribed"))
620                 return presence_unsubscribed(stream,from,to);
621         else if (!strcmp(type,"probe"))
622                 return presence_probe(stream,from,to);
623         else if (!strcmp(type,"error")){
624                 g_warning(N_("Error presence received: %s"),xmlnode2str(tag));
625                 return 0;
626         }
627
628         g_warning(N_("Unsupported type in %s"),xmlnode2str(tag));
629         presence_send_error(stream,to,from,501,_("Not Implemented"));
630         return -1;
631 }
632
Note: See TracBrowser for help on using the browser.