source: protocols/jabber/iq.c @ 88591fd

Last change on this file since 88591fd was 6baca2a, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-10-01T09:31:41Z

Some initial hooks/stuff for privacy lists, and fixed a crash bug on
connecting to Google Talk.

  • Property mode set to 100644
File size: 11.1 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - IQ packets                                               *
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_iq( struct xt_node *node, gpointer data )
27{
28        struct gaim_connection *gc = data;
29        struct jabber_data *jd = gc->proto_data;
30        struct xt_node *query, *reply = NULL, *orig = NULL, *c;
31        char *s, *type, *xmlns;
32        int st;
33       
34        query = xt_find_node( node->children, "query" );
35        type = xt_find_attr( node, "type" );
36       
37        if( !type )
38                return XT_HANDLED;      /* Ignore it for now, don't know what's best... */
39       
40        xmlns = xt_find_attr( query, "xmlns" );
41       
42        if( ( s = xt_find_attr( node, "id" ) ) )
43                orig = jabber_packet_from_cache( gc, s );
44       
45        if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 )
46        {
47                /* Time to authenticate ourselves! */
48                reply = xt_new_node( "query", NULL, NULL );
49                xt_add_attr( reply, "xmlns", "jabber:iq:auth" );
50                xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) );
51                xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) );
52               
53                if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) )
54                {
55                        /* We can do digest authentication, it seems, and of
56                           course we prefer that. */
57                        SHA_CTX sha;
58                        char hash_hex[40];
59                        unsigned char hash[20];
60                        int i;
61                       
62                        shaInit( &sha );
63                        shaUpdate( &sha, (unsigned char*) s, strlen( s ) );
64                        shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) );
65                        shaFinal( &sha, hash );
66                       
67                        for( i = 0; i < 20; i ++ )
68                                sprintf( hash_hex + i * 2, "%02x", hash[i] );
69                       
70                        xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) );
71                }
72                else if( xt_find_node( query->children, "password" ) )
73                {
74                        /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */
75                        xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) );
76                }
77                else
78                {
79                        xt_free_node( reply );
80                       
81                        hide_login_progress( gc, "Can't find suitable authentication method" );
82                        signoff( gc );
83                        return XT_ABORT;
84                }
85               
86                reply = jabber_make_packet( "iq", "set", NULL, reply );
87                jabber_cache_packet( gc, reply );
88                st = jabber_write_packet( gc, reply );
89               
90                return st ? XT_HANDLED : XT_ABORT;
91        }
92        if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:roster" ) == 0 )
93        {
94                struct xt_node *node;
95               
96                node = query->children;
97                while( ( node = xt_find_node( node, "item" ) ) )
98                {
99                        char *jid = xt_find_attr( node, "jid" );
100                        char *name = xt_find_attr( node, "name" );
101                        char *sub = xt_find_attr( node, "subscription" );
102                       
103                        if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
104                                add_buddy( gc, NULL, jid, name );
105                       
106                        node = node->next;
107                }
108               
109                account_online( gc );
110        }
111        if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:privacy" ) == 0 )
112        {
113                struct xt_node *node;
114               
115                /* When receiving a list of lists: */
116                if( ( node = xt_find_node( query->children, "active" ) ) )
117                {
118                        if( ( s = xt_find_attr( node, "name" ) ) )
119                        {
120                                set_t *set;
121                               
122                                g_free( jd->privacy_active );
123                                jd->privacy_active = g_strdup( s );
124                               
125                                /* Save it so the user can see it. */
126                                if( ( set = set_find( &gc->acc->set, "privacy_list" ) ) )
127                                {
128                                        g_free( set->value );
129                                        set->value = g_strdup( s );
130                                }
131                               
132                                if( !jabber_get_privacy( gc ) )
133                                        return XT_ABORT;
134                        }
135                }
136                /* When receiving an actual list: */
137                else if( ( node = xt_find_node( query->children, "list" ) ) )
138                {
139                        xt_free_node( jd->privacy_list );
140                        jd->privacy_list = xt_dup( node );
141                }
142                else if( query->children == NULL )
143                {
144                        /* What to do here if there is no privacy list defined yet... */
145                }
146        }
147        else if( strcmp( type, "result" ) == 0 && orig )
148        {
149                struct xt_node *c;
150                if( !( jd->flags & JFLAG_AUTHENTICATED ) &&
151                    ( c = xt_find_node( orig->children, "query" ) ) &&
152                    ( c = xt_find_node( c->children, "username" ) ) &&
153                    c->text_len )
154                {
155                        /* This happens when we just successfully authenticated
156                           the old (non-SASL) way. */
157                        jd->flags |= JFLAG_AUTHENTICATED;
158                        if( !jabber_get_roster( gc ) || !jabber_get_privacy( gc ) )
159                                return XT_ABORT;
160                }
161                /* Tricky: Look for <bind> in the reply, because the server
162                   should confirm the chosen resource string there. For
163                   <session>, however, look in the cache, because the server
164                   will probably not include it in its reply. */
165                else if( ( c = xt_find_node( node->children, "bind" ) ) ||
166                         ( c = xt_find_node( orig->children, "session" ) ) )
167                {
168                        if( strcmp( c->name, "bind" ) == 0 )
169                        {
170                                c = xt_find_node( c->children, "jid" );
171                                if( c && c->text_len && ( s = strchr( c->text, '/' ) ) &&
172                                    strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 )
173                                        serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 );
174                               
175                                jd->flags &= ~JFLAG_WAIT_BIND;
176                        }
177                        else if( strcmp( c->name, "session" ) == 0 )
178                                jd->flags &= ~JFLAG_WAIT_SESSION;
179                       
180                        if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
181                        {
182                                if( !jabber_get_roster( gc ) || !jabber_get_privacy( gc ) )
183                                        return XT_ABORT;
184                        }
185                }
186                else if( ( c = xt_find_node( orig->children, "query" ) ) &&
187                         ( c = xt_find_node( c->children, "active" ) ) )
188                {
189                        /* We just successfully activated a (different)
190                           privacy list. Fetch it now. */
191                        g_free( jd->privacy_active );
192                        jd->privacy_active = g_strdup( xt_find_attr( c, "name" ) );
193                       
194                        if( !jabber_get_privacy( gc ) )
195                                return XT_ABORT;
196                }
197        }
198        else if( strcmp( type, "error" ) == 0 )
199        {
200                if( !( jd->flags & JFLAG_AUTHENTICATED ) &&
201                    ( c = xt_find_node( orig->children, "query" ) ) &&
202                    ( c = xt_find_node( c->children, "username" ) ) &&
203                    c->text_len )
204                {
205                        hide_login_progress( gc, "Authentication failure" );
206                        signoff( gc );
207                        return XT_ABORT;
208                }
209                else if( orig &&
210                         ( c = xt_find_node( orig->children, "query" ) ) &&
211                         ( c = xt_find_node( c->children, "active" ) ) )
212                {
213                        serv_got_crap( gc, "Error while activating privacy list, maybe it doesn't exist" );
214                }
215        }
216       
217        return XT_HANDLED;
218}
219
220int jabber_start_iq_auth( struct gaim_connection *gc )
221{
222        struct jabber_data *jd = gc->proto_data;
223        struct xt_node *node;
224        int st;
225       
226        node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) );
227        xt_add_attr( node, "xmlns", "jabber:iq:auth" );
228        node = jabber_make_packet( "iq", "get", NULL, node );
229       
230        st = jabber_write_packet( gc, node );
231       
232        xt_free_node( node );
233        return st;
234}
235
236int jabber_get_roster( struct gaim_connection *gc )
237{
238        struct xt_node *node;
239        int st;
240       
241        set_login_progress( gc, 1, "Authenticated, requesting buddy list" );
242       
243        node = xt_new_node( "query", NULL, NULL );
244        xt_add_attr( node, "xmlns", "jabber:iq:roster" );
245        node = jabber_make_packet( "iq", "get", NULL, node );
246       
247        st = jabber_write_packet( gc, node );
248       
249        xt_free_node( node );
250        return st;
251}
252
253int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name )
254{
255        struct xt_node *node;
256        int st;
257       
258        /* Build the item entry */
259        node = xt_new_node( "item", NULL, NULL );
260        xt_add_attr( node, "jid", handle );
261        if( name )
262                xt_add_attr( node, "name", name );
263       
264        /* And pack it into a roster-add packet */
265        node = xt_new_node( "query", NULL, node );
266        xt_add_attr( node, "xmlns", "jabber:iq:roster" );
267        node = jabber_make_packet( "iq", "set", NULL, node );
268       
269        st = jabber_write_packet( gc, node );
270       
271        xt_free_node( node );
272        return st;
273}
274
275int jabber_remove_from_roster( struct gaim_connection *gc, char *handle )
276{
277        struct xt_node *node;
278        int st;
279       
280        /* Build the item entry */
281        node = xt_new_node( "item", NULL, NULL );
282        xt_add_attr( node, "jid", handle );
283        xt_add_attr( node, "subscription", "remove" );
284       
285        /* And pack it into a roster-add packet */
286        node = xt_new_node( "query", NULL, node );
287        xt_add_attr( node, "xmlns", "jabber:iq:roster" );
288        node = jabber_make_packet( "iq", "set", NULL, node );
289       
290        st = jabber_write_packet( gc, node );
291       
292        xt_free_node( node );
293        return st;
294}
295
296/* Request the privacy list from the server. We need this, because every
297   time we remove/add something we have to send the whole new list to the
298   server again... If no privacy list is specified yet, this function will
299   first ask for the list of lists (XMPP supports multiple "privacy lists",
300   don't ask me why), later we can then fetch the list we want to use. */
301int jabber_get_privacy( struct gaim_connection *gc )
302{
303        struct jabber_data *jd = gc->proto_data;
304        struct xt_node *node = NULL;
305        char *name;
306        int st;
307       
308        if( jd->privacy_active )
309        {
310                /* If we know what is the active list right now, fetch it. */
311                node = xt_new_node( "list", NULL, NULL );
312                xt_add_attr( node, "name", jd->privacy_active );
313        }
314        /* Okay, we don't know yet. If the user set a specific list, we'll
315           activate that one. Otherwise, we should figure out which list is
316           currently active. */
317        else if( ( name = set_getstr( &gc->acc->set, "privacy_list" ) ) )
318        {
319                return jabber_set_privacy( gc, name );
320        }
321        /* else: sending this packet without a <list/> element will give
322           a list of available lists and information about the currently
323           active list. */
324       
325        node = xt_new_node( "query", NULL, node );
326        xt_add_attr( node, "xmlns", "jabber:iq:privacy" );
327        node = jabber_make_packet( "iq", "get", NULL, node );
328       
329        st = jabber_write_packet( gc, node );
330       
331        xt_free_node( node );
332        return st;
333}
334
335int jabber_set_privacy( struct gaim_connection *gc, char *name )
336{
337        struct xt_node *node;
338       
339        node = xt_new_node( "active", NULL, NULL );
340        xt_add_attr( node, "name", name );
341        node = xt_new_node( "query", NULL, node );
342        xt_add_attr( node, "xmlns", "jabber:iq:privacy" );
343       
344        node = jabber_make_packet( "iq", "set", NULL, node );
345        jabber_cache_packet( gc, node );
346       
347        return jabber_write_packet( gc, node );
348}
Note: See TracBrowser for help on using the repository browser.