source: protocols/jabber/iq.c @ eded1f7

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

Merged in 280..288 from upstream (e.g. PING)

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