source: protocols/jabber/iq.c @ 1c3008a

Last change on this file since 1c3008a was 1c3008a, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-12-13T14:48:56Z

No functional changes, just some style "fixes". Although I admit I'm
somewhat growing out of my own coding style, I do try to keep things
consistent at least within files.

Comments are now in reviewboard:

http://code.bitlbee.org/rb/r/13/

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