source: protocols/jabber/iq.c @ 8a90001

Last change on this file since 8a90001 was 4358b10, checked in by ulim <a.sporto+bee@…>, at 2008-05-04T13:32:15Z

ulibc support, fixes "Invalid SOCKS5 Connect message" problem

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