source: protocols/jabber/presence.c @ dce3903

Last change on this file since dce3903 was 3a80471, checked in by Wilmer van der Gaast <wilmer@…>, at 2007-11-24T01:13:15Z

(Hopefully) fixing one case where the Jabber module doesn't understand a
<presence type=unavailable> tag properly and keeps showing the buddy as
on-line. (When the tag comes from a bare JID.)

  • Property mode set to 100644
File size: 7.5 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - Handling of presence (tags), etc                         *
5*                                                                           *
6*  Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net>                   *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include "jabber.h"
25
26xt_status jabber_pkt_presence( struct xt_node *node, gpointer data )
27{
28        struct im_connection *ic = data;
29        char *from = xt_find_attr( node, "from" );
30        char *type = xt_find_attr( node, "type" );      /* NULL should mean the person is online. */
31        struct xt_node *c;
32        struct jabber_buddy *bud;
33        int is_chat = 0, is_away = 0;
34        char *s;
35       
36        if( !from )
37                return XT_HANDLED;
38       
39        if( ( s = strchr( from, '/' ) ) )
40        {
41                *s = 0;
42                if( jabber_chat_by_name( ic, from ) )
43                        is_chat = 1;
44                *s = '/';
45        }
46       
47        if( type == NULL )
48        {
49                if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )
50                {
51                        if( set_getbool( &ic->irc->set, "debug" ) )
52                                imcb_log( ic, "WARNING: Could not handle presence information from JID: %s", from );
53                        return XT_HANDLED;
54                }
55               
56                g_free( bud->away_message );
57                if( ( c = xt_find_node( node->children, "status" ) ) && c->text_len > 0 )
58                        bud->away_message = g_strdup( c->text );
59                else
60                        bud->away_message = NULL;
61               
62                if( ( c = xt_find_node( node->children, "show" ) ) && c->text_len > 0 )
63                {
64                        bud->away_state = (void*) jabber_away_state_by_code( c->text );
65                        if( strcmp( c->text, "chat" ) != 0 )
66                                is_away = OPT_AWAY;
67                }
68                else
69                {
70                        bud->away_state = NULL;
71                        /* Let's only set last_act if there's *no* away state,
72                           since it could be some auto-away thingy. */
73                        bud->last_act = time( NULL );
74                }
75               
76                if( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 )
77                        bud->priority = atoi( c->text );
78                else
79                        bud->priority = 0;
80               
81                if( is_chat )
82                        jabber_chat_pkt_presence( ic, bud, node );
83                else if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) )
84                        imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away,
85                                           ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL,
86                                           bud->away_message );
87        }
88        else if( strcmp( type, "unavailable" ) == 0 )
89        {
90                if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
91                {
92                        if( set_getbool( &ic->irc->set, "debug" ) )
93                                imcb_log( ic, "WARNING: Received presence information from unknown JID: %s", from );
94                        return XT_HANDLED;
95                }
96               
97                /* Handle this before we delete the JID. */
98                if( is_chat )
99                {
100                        jabber_chat_pkt_presence( ic, bud, node );
101                }
102               
103                if( strchr( from, '/' ) == NULL )
104                        /* Sometimes servers send a type="unavailable" from a
105                           bare JID, which should mean that suddenly all
106                           resources for this JID disappeared. */
107                        jabber_buddy_remove_bare( ic, from );
108                else
109                        jabber_buddy_remove( ic, from );
110               
111                if( is_chat )
112                {
113                        /* Nothing else to do for now? */
114                }
115                else if( ( s = strchr( from, '/' ) ) )
116                {
117                        *s = 0;
118               
119                        /* If another resource is still available, send its presence
120                           information. */
121                        if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) )
122                        {
123                                if( bud->away_state && ( *bud->away_state->code == 0 ||
124                                    strcmp( bud->away_state->code, "chat" ) == 0 ) )
125                                        is_away = OPT_AWAY;
126                               
127                                imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away,
128                                                   ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL,
129                                                   bud->away_message );
130                        }
131                        else
132                        {
133                                /* Otherwise, count him/her as offline now. */
134                                imcb_buddy_status( ic, from, 0, NULL, NULL );
135                        }
136                       
137                        *s = '/';
138                }
139                else
140                {
141                        imcb_buddy_status( ic, from, 0, NULL, NULL );
142                }
143        }
144        else if( strcmp( type, "subscribe" ) == 0 )
145        {
146                jabber_buddy_ask( ic, from );
147        }
148        else if( strcmp( type, "subscribed" ) == 0 )
149        {
150                /* Not sure about this one, actually... */
151                imcb_log( ic, "%s just accepted your authorization request", from );
152        }
153        else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 )
154        {
155                /* Do nothing here. Plenty of control freaks or over-curious
156                   souls get excited when they can see who still has them in
157                   their buddy list and who finally removed them. Somehow I
158                   got the impression that those are the people who get
159                   removed from many buddy lists for "some" reason...
160                   
161                   If you're one of those people, this is your chance to write
162                   your first line of code in C... */
163        }
164        else if( strcmp( type, "error" ) == 0 )
165        {
166                struct jabber_error *err;
167               
168                if( ( c = xt_find_node( node->children, "error" ) ) )
169                {
170                        err = jabber_error_parse( c, XMLNS_STANZA_ERROR );
171                        imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name,
172                                    err->code, err->text ? ": " : "",
173                                    err->text ? err->text : "" );
174                        jabber_error_free( err );
175                }
176                /* What else to do with it? */
177        }
178       
179        return XT_HANDLED;
180}
181
182/* Whenever presence information is updated, call this function to inform the
183   server. */
184int presence_send_update( struct im_connection *ic )
185{
186        struct jabber_data *jd = ic->proto_data;
187        struct xt_node *node;
188        char *show = jd->away_state->code;
189        char *status = jd->away_message;
190        struct groupchat *c;
191        int st;
192       
193        node = jabber_make_packet( "presence", NULL, NULL, NULL );
194        xt_add_child( node, xt_new_node( "priority", set_getstr( &ic->acc->set, "priority" ), NULL ) );
195        if( show && *show )
196                xt_add_child( node, xt_new_node( "show", show, NULL ) );
197        if( status )
198                xt_add_child( node, xt_new_node( "status", status, NULL ) );
199       
200        st = jabber_write_packet( ic, node );
201       
202        /* Have to send this update to all groupchats too, the server won't
203           do this automatically. */
204        for( c = ic->groupchats; c && st; c = c->next )
205        {
206                struct jabber_chat *jc = c->data;
207               
208                xt_add_attr( node, "to", jc->my_full_jid );
209                st = jabber_write_packet( ic, node );
210        }
211       
212        xt_free_node( node );
213        return st;
214}
215
216/* Send a subscribe/unsubscribe request to a buddy. */
217int presence_send_request( struct im_connection *ic, char *handle, char *request )
218{
219        struct xt_node *node;
220        int st;
221       
222        node = jabber_make_packet( "presence", NULL, NULL, NULL );
223        xt_add_attr( node, "to", handle );
224        xt_add_attr( node, "type", request );
225       
226        st = jabber_write_packet( ic, node );
227       
228        xt_free_node( node );
229        return st;
230}
Note: See TracBrowser for help on using the repository browser.