source: protocols/jabber/iq.c @ dc0ba9c

Last change on this file since dc0ba9c was dc0ba9c, checked in by kenobi <kenobi@…>, at 2007-12-18T02:07:59Z

sending via proxy

  • Property mode set to 100644
File size: 21.9 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#include "sha1.h"
26
27static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
28static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
29
30xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
31{
32        struct im_connection *ic = data;
33        struct xt_node *c, *reply = NULL;
34        char *type, *s;
35        int st, pack = 1;
36       
37        type = xt_find_attr( node, "type" );
38       
39        if( !type )
40        {
41                imcb_error( ic, "Received IQ packet without type." );
42                imc_logout( ic, TRUE );
43                return XT_ABORT;
44        }
45       
46        if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 )
47        {
48                return jabber_cache_handle_packet( ic, node );
49        }
50        else if( strcmp( type, "get" ) == 0 )
51        {
52                if( !( c = xt_find_node( node->children, "query" ) ) ||
53                    !( s = xt_find_attr( c, "xmlns" ) ) )
54                {
55                        imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type );
56                        return XT_HANDLED;
57                }
58               
59                reply = xt_new_node( "query", NULL, NULL );
60                xt_add_attr( reply, "xmlns", s );
61               
62                /* Of course this is a very essential query to support. ;-) */
63                if( strcmp( s, XMLNS_VERSION ) == 0 )
64                {
65                        xt_add_child( reply, xt_new_node( "name", "BitlBee", NULL ) );
66                        xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) );
67                        xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) );
68                }
69                else if( strcmp( s, XMLNS_TIME ) == 0 )
70                {
71                        time_t time_ep;
72                        char buf[1024];
73                       
74                        buf[sizeof(buf)-1] = 0;
75                        time_ep = time( NULL );
76                       
77                        strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%S", gmtime( &time_ep ) );
78                        xt_add_child( reply, xt_new_node( "utc", buf, NULL ) );
79                       
80                        strftime( buf, sizeof( buf ) - 1, "%Z", localtime( &time_ep ) );
81                        xt_add_child( reply, xt_new_node( "tz", buf, NULL ) );
82                }
83                else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
84                {
85                        const char *features[] = { XMLNS_VERSION,
86                                                   XMLNS_TIME,
87                                                   XMLNS_CHATSTATES,
88                                                   XMLNS_MUC,
89                                                   XMLNS_SI,
90                                                   XMLNS_BYTESTREAMS,
91                                                   XMLNS_FILETRANSFER,
92                                                   NULL };
93                        const char **f;
94                       
95                        c = xt_new_node( "identity", NULL, NULL );
96                        xt_add_attr( c, "category", "client" );
97                        xt_add_attr( c, "type", "pc" );
98                        xt_add_attr( c, "name", "BitlBee" );
99                        xt_add_child( reply, c );
100                       
101                        for( f = features; *f; f ++ )
102                        {
103                                c = xt_new_node( "feature", NULL, NULL );
104                                xt_add_attr( c, "var", *f );
105                                xt_add_child( reply, c );
106                        }
107                }
108                else
109                {
110                        xt_free_node( reply );
111                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
112                        pack = 0;
113                }
114        }
115        else if( strcmp( type, "set" ) == 0 )
116        {
117                if(  ( c = xt_find_node( node->children, "si" ) ) &&
118                     ( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) )
119                {
120                        return jabber_si_handle_request( ic, node, c );
121                } else if( !( c = xt_find_node( node->children, "query" ) ) ||
122                    !( s = xt_find_attr( c, "xmlns" ) ) )
123                {
124                        imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type );
125                        return XT_HANDLED;
126                } else if( strcmp( s, XMLNS_ROSTER ) == 0 )
127                {
128                /* This is a roster push. XMPP servers send this when someone
129                   was added to (or removed from) the buddy list. AFAIK they're
130                   sent even if we added this buddy in our own session. */
131                        int bare_len = strlen( ic->acc->user );
132                       
133                        if( ( s = xt_find_attr( node, "from" ) ) == NULL ||
134                            ( strncmp( s, ic->acc->user, bare_len ) == 0 &&
135                              ( s[bare_len] == 0 || s[bare_len] == '/' ) ) )
136                        {
137                                jabber_parse_roster( ic, node, NULL );
138                               
139                                /* Should we generate a reply here? Don't think it's
140                                   very important... */
141                        }
142                        else
143                        {
144                                imcb_log( ic, "WARNING: %s tried to fake a roster push!", s ? s : "(unknown)" );
145                               
146                                xt_free_node( reply );
147                                reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
148                                pack = 0;
149                        }
150                } else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 )
151                {
152                        /* Bytestream Request (stage 2 of file transfer) */
153                        return jabber_bs_recv_request( ic, node, c );
154                } else
155                {
156                        xt_free_node( reply );
157                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
158                        pack = 0;
159                }
160        }
161       
162        /* If we recognized the xmlns and managed to generate a reply,
163           finish and send it. */
164        if( reply )
165        {
166                /* Normally we still have to pack it into an iq-result
167                   packet, but for errors, for example, we don't. */
168                if( pack )
169                {
170                        reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), reply );
171                        if( ( s = xt_find_attr( node, "id" ) ) )
172                                xt_add_attr( reply, "id", s );
173                }
174               
175                st = jabber_write_packet( ic, reply );
176                xt_free_node( reply );
177                if( !st )
178                        return XT_ABORT;
179        }
180       
181        return XT_HANDLED;
182}
183
184static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
185static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
186
187int jabber_init_iq_auth( struct im_connection *ic )
188{
189        struct jabber_data *jd = ic->proto_data;
190        struct xt_node *node;
191        int st;
192       
193        node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) );
194        xt_add_attr( node, "xmlns", XMLNS_AUTH );
195        node = jabber_make_packet( "iq", "get", NULL, node );
196       
197        jabber_cache_add( ic, node, jabber_do_iq_auth );
198        st = jabber_write_packet( ic, node );
199       
200        return st;
201}
202
203static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
204{
205        struct jabber_data *jd = ic->proto_data;
206        struct xt_node *reply, *query;
207        xt_status st;
208        char *s;
209       
210        if( !( query = xt_find_node( node->children, "query" ) ) )
211        {
212                imcb_log( ic, "WARNING: Received incomplete IQ packet while authenticating" );
213                imc_logout( ic, FALSE );
214                return XT_HANDLED;
215        }
216       
217        /* Time to authenticate ourselves! */
218        reply = xt_new_node( "query", NULL, NULL );
219        xt_add_attr( reply, "xmlns", XMLNS_AUTH );
220        xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) );
221        xt_add_child( reply, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) );
222       
223        if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) )
224        {
225                /* We can do digest authentication, it seems, and of
226                   course we prefer that. */
227                sha1_state_t sha;
228                char hash_hex[41];
229                unsigned char hash[20];
230                int i;
231               
232                sha1_init( &sha );
233                sha1_append( &sha, (unsigned char*) s, strlen( s ) );
234                sha1_append( &sha, (unsigned char*) ic->acc->pass, strlen( ic->acc->pass ) );
235                sha1_finish( &sha, hash );
236               
237                for( i = 0; i < 20; i ++ )
238                        sprintf( hash_hex + i * 2, "%02x", hash[i] );
239               
240                xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) );
241        }
242        else if( xt_find_node( query->children, "password" ) )
243        {
244                /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */
245                xt_add_child( reply, xt_new_node( "password", ic->acc->pass, NULL ) );
246        }
247        else
248        {
249                xt_free_node( reply );
250               
251                imcb_error( ic, "Can't find suitable authentication method" );
252                imc_logout( ic, FALSE );
253                return XT_ABORT;
254        }
255       
256        reply = jabber_make_packet( "iq", "set", NULL, reply );
257        jabber_cache_add( ic, reply, jabber_finish_iq_auth );
258        st = jabber_write_packet( ic, reply );
259       
260        return st ? XT_HANDLED : XT_ABORT;
261}
262
263static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
264{
265        struct jabber_data *jd = ic->proto_data;
266        char *type;
267       
268        if( !( type = xt_find_attr( node, "type" ) ) )
269        {
270                imcb_log( ic, "WARNING: Received incomplete IQ packet while authenticating" );
271                imc_logout( ic, FALSE );
272                return XT_HANDLED;
273        }
274       
275        if( strcmp( type, "error" ) == 0 )
276        {
277                imcb_error( ic, "Authentication failure" );
278                imc_logout( ic, FALSE );
279                return XT_ABORT;
280        }
281        else if( strcmp( type, "result" ) == 0 )
282        {
283                /* This happens when we just successfully authenticated the
284                   old (non-SASL) way. */
285                jd->flags |= JFLAG_AUTHENTICATED;
286                if( !jabber_get_roster( ic ) )
287                        return XT_ABORT;
288        }
289       
290        return XT_HANDLED;
291}
292
293xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
294{
295        struct jabber_data *jd = ic->proto_data;
296        struct xt_node *c;
297        char *s;
298       
299        if( ( c = xt_find_node( node->children, "bind" ) ) )
300        {
301                c = xt_find_node( c->children, "jid" );
302                if( c && c->text_len && ( s = strchr( c->text, '/' ) ) &&
303                    strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 )
304                        imcb_log( ic, "Server changed session resource string to `%s'", s + 1 );
305               
306                jd->flags &= ~JFLAG_WAIT_BIND;
307        }
308        else
309        {
310                jd->flags &= ~JFLAG_WAIT_SESSION;
311        }
312       
313        if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
314        {
315                if( !jabber_get_roster( ic ) )
316                        return XT_ABORT;
317        }
318       
319        return XT_HANDLED;
320}
321
322int jabber_get_roster( struct im_connection *ic )
323{
324        struct xt_node *node;
325        int st;
326       
327        imcb_log( ic, "Authenticated, requesting buddy list" );
328       
329        node = xt_new_node( "query", NULL, NULL );
330        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
331        node = jabber_make_packet( "iq", "get", NULL, node );
332       
333        jabber_cache_add( ic, node, jabber_parse_roster );
334        st = jabber_write_packet( ic, node );
335       
336        return st;
337}
338
339static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
340{
341        struct xt_node *query, *c;
342        int initial = ( orig != NULL );
343       
344        if( !( query = xt_find_node( node->children, "query" ) ) )
345        {
346                imcb_log( ic, "WARNING: Received NULL roster packet" );
347                return XT_HANDLED;
348        }
349       
350        c = query->children;
351        while( ( c = xt_find_node( c, "item" ) ) )
352        {
353                struct xt_node *group = xt_find_node( node->children, "group" );
354                char *jid = xt_find_attr( c, "jid" );
355                char *name = xt_find_attr( c, "name" );
356                char *sub = xt_find_attr( c, "subscription" );
357               
358                if( jid && sub )
359                {
360                        if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
361                        {
362                                if( initial || imcb_find_buddy( ic, jid ) == NULL )
363                                        imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
364                                                                   group->text : NULL );
365                               
366                                if( name )
367                                        imcb_rename_buddy( ic, jid, name );
368                        }
369                        else if( strcmp( sub, "remove" ) == 0 )
370                        {
371                                jabber_buddy_remove_bare( ic, jid );
372                                imcb_remove_buddy( ic, jid, NULL );
373                        }
374                }
375               
376                c = c->next;
377        }
378       
379        if( initial )
380                imcb_connected( ic );
381       
382        return XT_HANDLED;
383}
384
385int jabber_get_vcard( struct im_connection *ic, char *bare_jid )
386{
387        struct xt_node *node;
388       
389        if( strchr( bare_jid, '/' ) )
390                return 1;       /* This was an error, but return 0 should only be done if the connection died... */
391       
392        node = xt_new_node( "vCard", NULL, NULL );
393        xt_add_attr( node, "xmlns", XMLNS_VCARD );
394        node = jabber_make_packet( "iq", "get", bare_jid, node );
395       
396        jabber_cache_add( ic, node, jabber_iq_display_vcard );
397        return jabber_write_packet( ic, node );
398}
399
400static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
401{
402        struct xt_node *vc, *c, *sc; /* subchild, ic is already in use ;-) */
403        GString *reply;
404        char *s;
405       
406        if( ( s = xt_find_attr( node, "type" ) ) == NULL ||
407            strcmp( s, "result" ) != 0 ||
408            ( vc = xt_find_node( node->children, "vCard" ) ) == NULL )
409        {
410                s = xt_find_attr( orig, "to" ); /* If this returns NULL something's wrong.. */
411                imcb_log( ic, "Could not retrieve vCard of %s", s ? s : "(NULL)" );
412                return XT_HANDLED;
413        }
414       
415        s = xt_find_attr( orig, "to" );
416        reply = g_string_new( "vCard information for " );
417        reply = g_string_append( reply, s ? s : "(NULL)" );
418        reply = g_string_append( reply, ":\n" );
419       
420        /* I hate this format, I really do... */
421       
422        if( ( c = xt_find_node( vc->children, "FN" ) ) && c->text_len )
423                g_string_append_printf( reply, "Name: %s\n", c->text );
424       
425        if( ( c = xt_find_node( vc->children, "N" ) ) && c->children )
426        {
427                reply = g_string_append( reply, "Full name:" );
428               
429                if( ( sc = xt_find_node( c->children, "PREFIX" ) ) && sc->text_len )
430                        g_string_append_printf( reply, " %s", sc->text );
431                if( ( sc = xt_find_node( c->children, "GIVEN" ) ) && sc->text_len )
432                        g_string_append_printf( reply, " %s", sc->text );
433                if( ( sc = xt_find_node( c->children, "MIDDLE" ) ) && sc->text_len )
434                        g_string_append_printf( reply, " %s", sc->text );
435                if( ( sc = xt_find_node( c->children, "FAMILY" ) ) && sc->text_len )
436                        g_string_append_printf( reply, " %s", sc->text );
437                if( ( sc = xt_find_node( c->children, "SUFFIX" ) ) && sc->text_len )
438                        g_string_append_printf( reply, " %s", sc->text );
439               
440                reply = g_string_append_c( reply, '\n' );
441        }
442       
443        if( ( c = xt_find_node( vc->children, "NICKNAME" ) ) && c->text_len )
444                g_string_append_printf( reply, "Nickname: %s\n", c->text );
445       
446        if( ( c = xt_find_node( vc->children, "BDAY" ) ) && c->text_len )
447                g_string_append_printf( reply, "Date of birth: %s\n", c->text );
448       
449        /* Slightly alternative use of for... ;-) */
450        for( c = vc->children; ( c = xt_find_node( c, "EMAIL" ) ); c = c->next )
451        {
452                if( ( sc = xt_find_node( c->children, "USERID" ) ) == NULL || sc->text_len == 0 )
453                        continue;
454               
455                if( xt_find_node( c->children, "HOME" ) )
456                        s = "Home";
457                else if( xt_find_node( c->children, "WORK" ) )
458                        s = "Work";
459                else
460                        s = "Misc.";
461               
462                g_string_append_printf( reply, "%s e-mail address: %s\n", s, sc->text );
463        }
464       
465        if( ( c = xt_find_node( vc->children, "URL" ) ) && c->text_len )
466                g_string_append_printf( reply, "Homepage: %s\n", c->text );
467       
468        /* Slightly alternative use of for... ;-) */
469        for( c = vc->children; ( c = xt_find_node( c, "ADR" ) ); c = c->next )
470        {
471                if( xt_find_node( c->children, "HOME" ) )
472                        s = "Home";
473                else if( xt_find_node( c->children, "WORK" ) )
474                        s = "Work";
475                else
476                        s = "Misc.";
477               
478                g_string_append_printf( reply, "%s address: ", s );
479               
480                if( ( sc = xt_find_node( c->children, "STREET" ) ) && sc->text_len )
481                        g_string_append_printf( reply, "%s ", sc->text );
482                if( ( sc = xt_find_node( c->children, "EXTADR" ) ) && sc->text_len )
483                        g_string_append_printf( reply, "%s, ", sc->text );
484                if( ( sc = xt_find_node( c->children, "PCODE" ) ) && sc->text_len )
485                        g_string_append_printf( reply, "%s, ", sc->text );
486                if( ( sc = xt_find_node( c->children, "LOCALITY" ) ) && sc->text_len )
487                        g_string_append_printf( reply, "%s, ", sc->text );
488                if( ( sc = xt_find_node( c->children, "REGION" ) ) && sc->text_len )
489                        g_string_append_printf( reply, "%s, ", sc->text );
490                if( ( sc = xt_find_node( c->children, "CTRY" ) ) && sc->text_len )
491                        g_string_append_printf( reply, "%s", sc->text );
492               
493                if( reply->str[reply->len-2] == ',' )
494                        reply = g_string_truncate( reply, reply->len-2 );
495               
496                reply = g_string_append_c( reply, '\n' );
497        }
498       
499        for( c = vc->children; ( c = xt_find_node( c, "TEL" ) ); c = c->next )
500        {
501                if( ( sc = xt_find_node( c->children, "NUMBER" ) ) == NULL || sc->text_len == 0 )
502                        continue;
503               
504                if( xt_find_node( c->children, "HOME" ) )
505                        s = "Home";
506                else if( xt_find_node( c->children, "WORK" ) )
507                        s = "Work";
508                else
509                        s = "Misc.";
510               
511                g_string_append_printf( reply, "%s phone number: %s\n", s, sc->text );
512        }
513       
514        if( ( c = xt_find_node( vc->children, "DESC" ) ) && c->text_len )
515                g_string_append_printf( reply, "Other information:\n%s", c->text );
516       
517        /* *sigh* */
518       
519        imcb_log( ic, "%s", reply->str );
520        g_string_free( reply, TRUE );
521       
522        return XT_HANDLED;
523}
524
525int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name )
526{
527        struct xt_node *node;
528        int st;
529       
530        /* Build the item entry */
531        node = xt_new_node( "item", NULL, NULL );
532        xt_add_attr( node, "jid", handle );
533        if( name )
534                xt_add_attr( node, "name", name );
535       
536        /* And pack it into a roster-add packet */
537        node = xt_new_node( "query", NULL, node );
538        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
539        node = jabber_make_packet( "iq", "set", NULL, node );
540       
541        st = jabber_write_packet( ic, node );
542       
543        xt_free_node( node );
544        return st;
545}
546
547int jabber_remove_from_roster( struct im_connection *ic, char *handle )
548{
549        struct xt_node *node;
550        int st;
551       
552        /* Build the item entry */
553        node = xt_new_node( "item", NULL, NULL );
554        xt_add_attr( node, "jid", handle );
555        xt_add_attr( node, "subscription", "remove" );
556       
557        /* And pack it into a roster-add packet */
558        node = xt_new_node( "query", NULL, node );
559        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
560        node = jabber_make_packet( "iq", "set", NULL, node );
561       
562        st = jabber_write_packet( ic, node );
563       
564        xt_free_node( node );
565        return st;
566}
567
568xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
569
570xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
571{
572        struct xt_node *node, *query;
573        struct jabber_buddy *bud;
574       
575        if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
576        {
577                /* Who cares about the unknown... */
578                imcb_log( ic, "Couldnt find the man: %s", bare_jid);
579                return 0;
580        }
581       
582        if( bud->features ) /* been here already */
583                return XT_HANDLED;
584       
585        node = xt_new_node( "query", NULL, NULL );
586        xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
587       
588        if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
589        {
590                imcb_log( ic, "WARNING: Couldn't generate feature query" );
591                xt_free_node( node );
592        }
593
594        jabber_cache_add( ic, query, jabber_iq_parse_features );
595
596        return jabber_write_packet( ic, query );
597}
598
599xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
600{
601        struct xt_node *c;
602        struct jabber_buddy *bud;
603        char *feature;
604
605        if( !( c = xt_find_node( node->children, "query" ) ) ||
606            !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) )
607        {
608                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
609                return XT_HANDLED;
610        }
611        if( ( bud = jabber_buddy_by_jid( ic, xt_find_attr( node, "from") , 0 ) ) == NULL )
612        {
613                /* Who cares about the unknown... */
614                imcb_log( ic, "Couldnt find the man: %s", xt_find_attr( node, "from"));
615                return 0;
616        }
617       
618        c = c->children;
619        while( ( c = xt_find_node( c, "feature" ) ) ) {
620                feature = xt_find_attr( c, "var" );
621                bud->features = g_slist_append(bud->features, g_strdup(feature) );
622                c = c->next;
623        }
624
625        return XT_HANDLED;
626}
627
628xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
629
630xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
631{
632        struct xt_node *node, *query;
633        struct jabber_data *jd = ic->proto_data;
634       
635        node = xt_new_node( "query", NULL, NULL );
636        xt_add_attr( node, "xmlns", xmlns );
637       
638        if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
639        {
640                imcb_log( ic, "WARNING: Couldn't generate server query" );
641                xt_free_node( node );
642        }
643
644        jd->have_streamhosts--;
645        jabber_cache_add( ic, query, jabber_iq_parse_server_features );
646
647        return jabber_write_packet( ic, query );
648}
649
650/*
651 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
652 */
653xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
654{
655        struct xt_node *c;
656        struct jabber_data *jd = ic->proto_data;
657
658        if( !( c = xt_find_node( node->children, "query" ) ) ||
659            !xt_find_attr( node, "from" ) )
660        {
661                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
662                return XT_HANDLED;
663        }
664
665        jd->have_streamhosts++;
666
667        if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_ITEMS ) == 0 )
668        {
669                char *item, *itemjid;
670
671                /* answer from server */
672       
673                c = c->children;
674                while( ( c = xt_find_node( c, "item" ) ) )
675                {
676                        item = xt_find_attr( c, "name" );
677                        itemjid = xt_find_attr( c, "jid" );
678
679                        jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
680
681                        c = c->next;
682                }
683        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 )
684        {
685                char *category, *type;
686
687                /* answer from potential proxy */
688
689                c = c->children;
690                while( ( c = xt_find_node( c, "identity" ) ) )
691                {
692                        category = xt_find_attr( c, "category" );
693                        type = xt_find_attr( c, "type" );
694
695                        if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
696                            category && ( strcmp( category, "proxy" ) == 0 ) )
697                                jabber_iq_query_server( ic, xt_find_attr( node, "from" ), XMLNS_BYTESTREAMS );
698
699                        c = c->next;
700                }
701        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_BYTESTREAMS ) == 0 )
702        {
703                char *host, *jid;
704                int port;
705
706                /* answer from proxy */
707
708                if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
709                    ( host = xt_find_attr( c, "host" ) ) &&
710                    ( port = atoi( xt_find_attr( c, "port" ) ) ) &&
711                    ( jid = xt_find_attr( c, "jid" ) ) )
712                {
713                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
714                        sh->jid = g_strdup( jid );
715                        sh->host = g_strdup( host );
716                        sprintf( sh->port, "%u", port );
717
718                        imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
719                        jd->streamhosts = g_slist_append( jd->streamhosts, sh );
720                }
721        }
722
723        if( jd->have_streamhosts == 0 )
724                jd->have_streamhosts++;
725        return XT_HANDLED;
726}
Note: See TracBrowser for help on using the repository browser.