source: protocols/jabber/iq.c @ 038d17f

Last change on this file since 038d17f was 038d17f, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-10-08T16:11:16Z

Implemented a better node cache using a GLib hash, and preparing to add
event handlers that can be set when sending a packet to handle the reply
to this specific packet. This should allow me to make the iq handler a
lot cleaner.

  • Property mode set to 100644
File size: 7.8 KB
RevLine 
[f06894d]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{
[21167d2]28        struct gaim_connection *gc = data;
29        struct jabber_data *jd = gc->proto_data;
[6baca2a]30        struct xt_node *query, *reply = NULL, *orig = NULL, *c;
[70f6aab8]31        char *s, *type, *xmlns;
[21167d2]32        int st;
33       
34        query = xt_find_node( node->children, "query" );
[70f6aab8]35        type = xt_find_attr( node, "type" );
[f06894d]36       
[70f6aab8]37        if( !type )
[21167d2]38                return XT_HANDLED;      /* Ignore it for now, don't know what's best... */
39       
[70f6aab8]40        xmlns = xt_find_attr( query, "xmlns" );
41       
[fe7a554]42        if( ( s = xt_find_attr( node, "id" ) ) )
[038d17f]43                orig = jabber_cache_get( gc, s );
[fe7a554]44       
[70f6aab8]45        if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 )
[21167d2]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                       
[70f6aab8]81                        hide_login_progress( gc, "Can't find suitable authentication method" );
[21167d2]82                        signoff( gc );
83                        return XT_ABORT;
84                }
85               
86                reply = jabber_make_packet( "iq", "set", NULL, reply );
[038d17f]87                jabber_cache_add( gc, reply );
[21167d2]88                st = jabber_write_packet( gc, reply );
89               
90                return st ? XT_HANDLED : XT_ABORT;
91        }
[0b4a0db]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               
[5e202b0]109                account_online( gc );
[0b4a0db]110        }
[fe7a554]111        else if( strcmp( type, "result" ) == 0 && orig )
[70f6aab8]112        {
[8e6c732]113                struct xt_node *c;
[995913b]114               
[fe7a554]115                if( !( jd->flags & JFLAG_AUTHENTICATED ) &&
[8e6c732]116                    ( c = xt_find_node( orig->children, "query" ) ) &&
117                    ( c = xt_find_node( c->children, "username" ) ) &&
118                    c->text_len )
[70f6aab8]119                {
[fe7a554]120                        /* This happens when we just successfully authenticated
121                           the old (non-SASL) way. */
[70f6aab8]122                        jd->flags |= JFLAG_AUTHENTICATED;
[090f1cb]123                        if( !jabber_get_roster( gc ) )
[70f6aab8]124                                return XT_ABORT;
125                }
[8e6c732]126                /* Tricky: Look for <bind> in the reply, because the server
127                   should confirm the chosen resource string there. For
128                   <session>, however, look in the cache, because the server
129                   will probably not include it in its reply. */
130                else if( ( c = xt_find_node( node->children, "bind" ) ) ||
131                         ( c = xt_find_node( orig->children, "session" ) ) )
[fe7a554]132                {
[8e6c732]133                        if( strcmp( c->name, "bind" ) == 0 )
134                        {
135                                c = xt_find_node( c->children, "jid" );
136                                if( c && c->text_len && ( s = strchr( c->text, '/' ) ) &&
137                                    strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 )
138                                        serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 );
139                               
[fe7a554]140                                jd->flags &= ~JFLAG_WAIT_BIND;
[8e6c732]141                        }
142                        else if( strcmp( c->name, "session" ) == 0 )
[fe7a554]143                                jd->flags &= ~JFLAG_WAIT_SESSION;
144                       
145                        if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
146                        {
[090f1cb]147                                if( !jabber_get_roster( gc ) )
[fe7a554]148                                        return XT_ABORT;
149                        }
150                }
[70f6aab8]151        }
152        else if( strcmp( type, "error" ) == 0 )
153        {
[6baca2a]154                if( !( jd->flags & JFLAG_AUTHENTICATED ) &&
[995913b]155                      orig &&
[6baca2a]156                    ( c = xt_find_node( orig->children, "query" ) ) &&
157                    ( c = xt_find_node( c->children, "username" ) ) &&
158                    c->text_len )
[70f6aab8]159                {
160                        hide_login_progress( gc, "Authentication failure" );
161                        signoff( gc );
162                        return XT_ABORT;
163                }
164        }
[f06894d]165       
166        return XT_HANDLED;
167}
168
[8d74291]169int jabber_start_iq_auth( struct gaim_connection *gc )
[21167d2]170{
171        struct jabber_data *jd = gc->proto_data;
172        struct xt_node *node;
173        int st;
174       
175        node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) );
176        xt_add_attr( node, "xmlns", "jabber:iq:auth" );
177        node = jabber_make_packet( "iq", "get", NULL, node );
178       
179        st = jabber_write_packet( gc, node );
180       
181        xt_free_node( node );
182        return st;
183}
[70f6aab8]184
185int jabber_get_roster( struct gaim_connection *gc )
186{
187        struct xt_node *node;
188        int st;
189       
190        set_login_progress( gc, 1, "Authenticated, requesting buddy list" );
191       
192        node = xt_new_node( "query", NULL, NULL );
193        xt_add_attr( node, "xmlns", "jabber:iq:roster" );
194        node = jabber_make_packet( "iq", "get", NULL, node );
195       
196        st = jabber_write_packet( gc, node );
197       
198        xt_free_node( node );
199        return st;
200}
[cfbb3a6]201
202int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name )
203{
204        struct xt_node *node;
205        int st;
206       
207        /* Build the item entry */
208        node = xt_new_node( "item", NULL, NULL );
209        xt_add_attr( node, "jid", handle );
210        if( name )
211                xt_add_attr( node, "name", name );
212       
213        /* And pack it into a roster-add packet */
214        node = xt_new_node( "query", NULL, node );
215        xt_add_attr( node, "xmlns", "jabber:iq:roster" );
216        node = jabber_make_packet( "iq", "set", NULL, node );
217       
218        st = jabber_write_packet( gc, node );
219       
220        xt_free_node( node );
221        return st;
222}
223
224int jabber_remove_from_roster( struct gaim_connection *gc, char *handle )
225{
226        struct xt_node *node;
227        int st;
228       
229        /* Build the item entry */
230        node = xt_new_node( "item", NULL, NULL );
231        xt_add_attr( node, "jid", handle );
232        xt_add_attr( node, "subscription", "remove" );
233       
234        /* And pack it into a roster-add packet */
235        node = xt_new_node( "query", NULL, node );
236        xt_add_attr( node, "xmlns", "jabber:iq:roster" );
237        node = jabber_make_packet( "iq", "set", NULL, node );
238       
239        st = jabber_write_packet( gc, node );
240       
241        xt_free_node( node );
242        return st;
243}
Note: See TracBrowser for help on using the repository browser.