source: protocols/jabber/presence.c @ 07ff8a2

Last change on this file since 07ff8a2 was e7f8838, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-01-11T13:17:11Z

Fixing bug #344, now away states should always be correct, even when people
do complicated things with multiple resources. (There were two bugs and
some duplicated code, so I moved things around a bit.)

  • Property mode set to 100644
File size: 7.4 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, *send_presence = NULL;
33        int is_chat = 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_jid( 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                }
66                else
67                {
68                        bud->away_state = NULL;
69                        /* Let's only set last_act if there's *no* away state,
70                           since it could be some auto-away thingy. */
71                        bud->last_act = time( NULL );
72                }
73               
74                if( ( c = xt_find_node( node->children, "priority" ) ) && c->text_len > 0 )
75                        bud->priority = atoi( c->text );
76                else
77                        bud->priority = 0;
78               
79                if( is_chat )
80                        jabber_chat_pkt_presence( ic, bud, node );
81                else
82                        send_presence = jabber_buddy_by_jid( ic, bud->bare_jid, 0 );
83        }
84        else if( strcmp( type, "unavailable" ) == 0 )
85        {
86                if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
87                {
88                        if( set_getbool( &ic->irc->set, "debug" ) )
89                                imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from );
90                        return XT_HANDLED;
91                }
92               
93                /* Handle this before we delete the JID. */
94                if( is_chat )
95                {
96                        jabber_chat_pkt_presence( ic, bud, node );
97                }
98               
99                if( strchr( from, '/' ) == NULL )
100                        /* Sometimes servers send a type="unavailable" from a
101                           bare JID, which should mean that suddenly all
102                           resources for this JID disappeared. */
103                        jabber_buddy_remove_bare( ic, from );
104                else
105                        jabber_buddy_remove( ic, from );
106               
107                if( is_chat )
108                {
109                        /* Nothing else to do for now? */
110                }
111                else if( ( s = strchr( from, '/' ) ) )
112                {
113                        *s = 0;
114               
115                        /* If another resource is still available, send its presence
116                           information. */
117                        if( ( send_presence = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
118                        {
119                                /* Otherwise, count him/her as offline now. */
120                                imcb_buddy_status( ic, from, 0, NULL, NULL );
121                        }
122                       
123                        *s = '/';
124                }
125                else
126                {
127                        imcb_buddy_status( ic, from, 0, NULL, NULL );
128                }
129        }
130        else if( strcmp( type, "subscribe" ) == 0 )
131        {
132                jabber_buddy_ask( ic, from );
133        }
134        else if( strcmp( type, "subscribed" ) == 0 )
135        {
136                /* Not sure about this one, actually... */
137                imcb_log( ic, "%s just accepted your authorization request", from );
138        }
139        else if( strcmp( type, "unsubscribe" ) == 0 || strcmp( type, "unsubscribed" ) == 0 )
140        {
141                /* Do nothing here. Plenty of control freaks or over-curious
142                   souls get excited when they can see who still has them in
143                   their buddy list and who finally removed them. Somehow I
144                   got the impression that those are the people who get
145                   removed from many buddy lists for "some" reason...
146                   
147                   If you're one of those people, this is your chance to write
148                   your first line of code in C... */
149        }
150        else if( strcmp( type, "error" ) == 0 )
151        {
152                return jabber_cache_handle_packet( ic, node );
153               
154                /*
155                struct jabber_error *err;
156                if( ( c = xt_find_node( node->children, "error" ) ) )
157                {
158                        err = jabber_error_parse( c, XMLNS_STANZA_ERROR );
159                        imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name,
160                                    err->code, err->text ? ": " : "",
161                                    err->text ? err->text : "" );
162                        jabber_error_free( err );
163                } */
164        }
165
166        if( send_presence )
167        {
168                int is_away;
169
170                if( send_presence->away_state && !( *send_presence->away_state->code == 0 ||
171                    strcmp( send_presence->away_state->code, "chat" ) == 0 ) )
172                        is_away = OPT_AWAY;
173
174                imcb_buddy_status( ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away,
175                                   ( is_away && send_presence->away_state ) ?
176                                   send_presence->away_state->full_name : NULL,
177                                   send_presence->away_message );
178        }
179       
180        return XT_HANDLED;
181}
182
183/* Whenever presence information is updated, call this function to inform the
184   server. */
185int presence_send_update( struct im_connection *ic )
186{
187        struct jabber_data *jd = ic->proto_data;
188        struct xt_node *node;
189        char *show = jd->away_state->code;
190        char *status = jd->away_message;
191        struct groupchat *c;
192        int st;
193       
194        node = jabber_make_packet( "presence", NULL, NULL, NULL );
195        xt_add_child( node, xt_new_node( "priority", set_getstr( &ic->acc->set, "priority" ), NULL ) );
196        if( show && *show )
197                xt_add_child( node, xt_new_node( "show", show, NULL ) );
198        if( status )
199                xt_add_child( node, xt_new_node( "status", status, NULL ) );
200       
201        st = jabber_write_packet( ic, node );
202       
203        /* Have to send this update to all groupchats too, the server won't
204           do this automatically. */
205        for( c = ic->groupchats; c && st; c = c->next )
206        {
207                struct jabber_chat *jc = c->data;
208               
209                xt_add_attr( node, "to", jc->my_full_jid );
210                st = jabber_write_packet( ic, node );
211        }
212       
213        xt_free_node( node );
214        return st;
215}
216
217/* Send a subscribe/unsubscribe request to a buddy. */
218int presence_send_request( struct im_connection *ic, char *handle, char *request )
219{
220        struct xt_node *node;
221        int st;
222       
223        node = jabber_make_packet( "presence", NULL, NULL, NULL );
224        xt_add_attr( node, "to", handle );
225        xt_add_attr( node, "type", request );
226       
227        st = jabber_write_packet( ic, node );
228       
229        xt_free_node( node );
230        return st;
231}
Note: See TracBrowser for help on using the repository browser.