source: protocols/jabber/iq.c @ 0cab388

Last change on this file since 0cab388 was b79308b, checked in by ulim <a.sporto+bee@…>, at 2008-04-14T13:10:53Z

merged in upstream r379 (somewhere after 1.2-3).
Just one trivial conflict in the jabber Makefile, went smoothly.

  • Property mode set to 100644
File size: 23.1 KB
RevLine 
[f06894d]1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - IQ packets                                               *
5*                                                                           *
6*  Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net>                   *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include "jabber.h"
[77bfd07]25#include "sha1.h"
[f06894d]26
[0da65d5]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 );
[abbd8ed]29
[f06894d]30xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
31{
[0da65d5]32        struct im_connection *ic = data;
[58b5f62]33        struct xt_node *c, *reply = NULL;
[861c199]34        char *type, *s;
[259edd4]35        int st, pack = 1;
[21167d2]36       
[70f6aab8]37        type = xt_find_attr( node, "type" );
[f06894d]38       
[70f6aab8]39        if( !type )
[861c199]40        {
[84b045d]41                imcb_error( ic, "Received IQ packet without type." );
[c2fb3809]42                imc_logout( ic, TRUE );
[861c199]43                return XT_ABORT;
44        }
[21167d2]45       
[58b5f62]46        if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 )
[861c199]47        {
[4306d8b]48                return jabber_cache_handle_packet( ic, node );
[861c199]49        }
[58b5f62]50        else if( strcmp( type, "get" ) == 0 )
51        {
[eded1f7]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/> ????? */
[58b5f62]54                    !( s = xt_find_attr( c, "xmlns" ) ) )
55                {
[43462708]56                        imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
[58b5f62]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. ;-) */
[47d3ac4]64                if( strcmp( s, XMLNS_VERSION ) == 0 )
[58b5f62]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                }
[47d3ac4]70                else if( strcmp( s, XMLNS_TIME ) == 0 )
[a4effbf]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                }
[eded1f7]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                }
[dc0ba9c]92                else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
[58b5f62]93                {
[1ba7e8f]94                        const char *features[] = { XMLNS_DISCO_INFO,
[8c1eb80]95                                                   XMLNS_VERSION,
[40ef702]96                                                   XMLNS_TIME,
97                                                   XMLNS_CHATSTATES,
98                                                   XMLNS_MUC,
[eded1f7]99                                                   XMLNS_PING,
[2c2df7d]100                                                   XMLNS_SI,
101                                                   XMLNS_BYTESTREAMS,
102                                                   XMLNS_FILETRANSFER,
[40ef702]103                                                   NULL };
104                        const char **f;
105                       
[58b5f62]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                       
[40ef702]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                        }
[58b5f62]118                }
119                else
120                {
121                        xt_free_node( reply );
[2c2df7d]122                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
[259edd4]123                        pack = 0;
[58b5f62]124                }
[259edd4]125        }
126        else if( strcmp( type, "set" ) == 0 )
127        {
[2c2df7d]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" ) ) ||
[dfa41a4]133                    !( s = xt_find_attr( c, "xmlns" ) ) )
134                {
[43462708]135                        imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
[dfa41a4]136                        return XT_HANDLED;
[2c2df7d]137                } else if( strcmp( s, XMLNS_ROSTER ) == 0 )
138                {
[9bcbe48]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. */
[0da65d5]142                        int bare_len = strlen( ic->acc->user );
[abbd8ed]143                       
144                        if( ( s = xt_find_attr( node, "from" ) ) == NULL ||
[0da65d5]145                            ( strncmp( s, ic->acc->user, bare_len ) == 0 &&
[abbd8ed]146                              ( s[bare_len] == 0 || s[bare_len] == '/' ) ) )
147                        {
[0da65d5]148                                jabber_parse_roster( ic, node, NULL );
[abbd8ed]149                               
150                                /* Should we generate a reply here? Don't think it's
151                                   very important... */
152                        }
153                        else
154                        {
[43462708]155                                imcb_log( ic, "Warning: %s tried to fake a roster push!", s ? s : "(unknown)" );
[abbd8ed]156                               
157                                xt_free_node( reply );
[2c2df7d]158                                reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
[abbd8ed]159                                pack = 0;
160                        }
[2c2df7d]161                } else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 )
162                {
163                        /* Bytestream Request (stage 2 of file transfer) */
[2ff2076]164                        return jabber_bs_recv_request( ic, node, c );
[2c2df7d]165                } else
[dfa41a4]166                {
167                        xt_free_node( reply );
[2c2df7d]168                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
[dfa41a4]169                        pack = 0;
170                }
[259edd4]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 )
[58b5f62]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                }
[259edd4]185               
[0da65d5]186                st = jabber_write_packet( ic, reply );
[259edd4]187                xt_free_node( reply );
188                if( !st )
189                        return XT_ABORT;
[58b5f62]190        }
[70f6aab8]191       
[861c199]192        return XT_HANDLED;
193}
194
[0da65d5]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 );
[861c199]197
[0da65d5]198int jabber_init_iq_auth( struct im_connection *ic )
[861c199]199{
[0da65d5]200        struct jabber_data *jd = ic->proto_data;
[861c199]201        struct xt_node *node;
202        int st;
[fe7a554]203       
[861c199]204        node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) );
[47d3ac4]205        xt_add_attr( node, "xmlns", XMLNS_AUTH );
[861c199]206        node = jabber_make_packet( "iq", "get", NULL, node );
207       
[0da65d5]208        jabber_cache_add( ic, node, jabber_do_iq_auth );
209        st = jabber_write_packet( ic, node );
[861c199]210       
211        return st;
212}
213
[0da65d5]214static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[861c199]215{
[0da65d5]216        struct jabber_data *jd = ic->proto_data;
[861c199]217        struct xt_node *reply, *query;
218        xt_status st;
219        char *s;
220       
[9bcbe48]221        if( !( query = xt_find_node( node->children, "query" ) ) )
222        {
[43462708]223                imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" );
[c2fb3809]224                imc_logout( ic, FALSE );
[9bcbe48]225                return XT_HANDLED;
226        }
[861c199]227       
228        /* Time to authenticate ourselves! */
229        reply = xt_new_node( "query", NULL, NULL );
[47d3ac4]230        xt_add_attr( reply, "xmlns", XMLNS_AUTH );
[861c199]231        xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) );
[0da65d5]232        xt_add_child( reply, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) );
[861c199]233       
234        if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) )
[21167d2]235        {
[861c199]236                /* We can do digest authentication, it seems, and of
237                   course we prefer that. */
[77bfd07]238                sha1_state_t sha;
[e727608]239                char hash_hex[41];
[861c199]240                unsigned char hash[20];
241                int i;
[21167d2]242               
[77bfd07]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 );
[21167d2]247               
[861c199]248                for( i = 0; i < 20; i ++ )
249                        sprintf( hash_hex + i * 2, "%02x", hash[i] );
[21167d2]250               
[861c199]251                xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) );
[21167d2]252        }
[861c199]253        else if( xt_find_node( query->children, "password" ) )
[0b4a0db]254        {
[861c199]255                /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */
[0da65d5]256                xt_add_child( reply, xt_new_node( "password", ic->acc->pass, NULL ) );
[0b4a0db]257        }
[861c199]258        else
[70f6aab8]259        {
[861c199]260                xt_free_node( reply );
[995913b]261               
[84b045d]262                imcb_error( ic, "Can't find suitable authentication method" );
[c2fb3809]263                imc_logout( ic, FALSE );
[861c199]264                return XT_ABORT;
[70f6aab8]265        }
[861c199]266       
267        reply = jabber_make_packet( "iq", "set", NULL, reply );
[0da65d5]268        jabber_cache_add( ic, reply, jabber_finish_iq_auth );
269        st = jabber_write_packet( ic, reply );
[861c199]270       
271        return st ? XT_HANDLED : XT_ABORT;
272}
273
[0da65d5]274static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[861c199]275{
[0da65d5]276        struct jabber_data *jd = ic->proto_data;
[9bcbe48]277        char *type;
278       
279        if( !( type = xt_find_attr( node, "type" ) ) )
280        {
[43462708]281                imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" );
[c2fb3809]282                imc_logout( ic, FALSE );
[9bcbe48]283                return XT_HANDLED;
284        }
[861c199]285       
286        if( strcmp( type, "error" ) == 0 )
[70f6aab8]287        {
[84b045d]288                imcb_error( ic, "Authentication failure" );
[c2fb3809]289                imc_logout( ic, FALSE );
[861c199]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;
[0da65d5]297                if( !jabber_get_roster( ic ) )
[70f6aab8]298                        return XT_ABORT;
299        }
[f06894d]300       
301        return XT_HANDLED;
302}
303
[0da65d5]304xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[21167d2]305{
[0da65d5]306        struct jabber_data *jd = ic->proto_data;
[861c199]307        struct xt_node *c;
308        char *s;
[21167d2]309       
[861c199]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, '/' ) ) &&
[0da65d5]314                    strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 )
[84b045d]315                        imcb_log( ic, "Server changed session resource string to `%s'", s + 1 );
[861c199]316               
317                jd->flags &= ~JFLAG_WAIT_BIND;
318        }
319        else
320        {
321                jd->flags &= ~JFLAG_WAIT_SESSION;
322        }
[21167d2]323       
[861c199]324        if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
325        {
[0da65d5]326                if( !jabber_get_roster( ic ) )
[861c199]327                        return XT_ABORT;
328        }
[21167d2]329       
[861c199]330        return XT_HANDLED;
[21167d2]331}
[70f6aab8]332
[0da65d5]333int jabber_get_roster( struct im_connection *ic )
[70f6aab8]334{
335        struct xt_node *node;
336        int st;
337       
[84b045d]338        imcb_log( ic, "Authenticated, requesting buddy list" );
[70f6aab8]339       
340        node = xt_new_node( "query", NULL, NULL );
[47d3ac4]341        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
[70f6aab8]342        node = jabber_make_packet( "iq", "get", NULL, node );
343       
[0da65d5]344        jabber_cache_add( ic, node, jabber_parse_roster );
345        st = jabber_write_packet( ic, node );
[70f6aab8]346       
347        return st;
348}
[cfbb3a6]349
[0da65d5]350static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[861c199]351{
352        struct xt_node *query, *c;
[abbd8ed]353        int initial = ( orig != NULL );
[861c199]354       
[9bcbe48]355        if( !( query = xt_find_node( node->children, "query" ) ) )
356        {
[43462708]357                imcb_log( ic, "Warning: Received NULL roster packet" );
[9bcbe48]358                return XT_HANDLED;
359        }
[861c199]360       
361        c = query->children;
362        while( ( c = xt_find_node( c, "item" ) ) )
363        {
[f0cb961]364                struct xt_node *group = xt_find_node( node->children, "group" );
[861c199]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               
[f0cb961]369                if( jid && sub )
[abbd8ed]370                {
371                        if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
372                        {
[f0cb961]373                                if( initial || imcb_find_buddy( ic, jid ) == NULL )
374                                        imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
375                                                                   group->text : NULL );
376                               
[d06eabf]377                                if( name )
378                                        imcb_rename_buddy( ic, jid, name );
[abbd8ed]379                        }
380                        else if( strcmp( sub, "remove" ) == 0 )
381                        {
[0da65d5]382                                jabber_buddy_remove_bare( ic, jid );
[998b103]383                                imcb_remove_buddy( ic, jid, NULL );
[abbd8ed]384                        }
385                }
[861c199]386               
387                c = c->next;
388        }
389       
[abbd8ed]390        if( initial )
[84b045d]391                imcb_connected( ic );
[861c199]392       
393        return XT_HANDLED;
394}
395
[0da65d5]396int jabber_get_vcard( struct im_connection *ic, char *bare_jid )
[1991be6]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 );
[47d3ac4]404        xt_add_attr( node, "xmlns", XMLNS_VCARD );
[1991be6]405        node = jabber_make_packet( "iq", "get", bare_jid, node );
406       
[0da65d5]407        jabber_cache_add( ic, node, jabber_iq_display_vcard );
408        return jabber_write_packet( ic, node );
[1991be6]409}
410
[0da65d5]411static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[1991be6]412{
[0da65d5]413        struct xt_node *vc, *c, *sc; /* subchild, ic is already in use ;-) */
[1991be6]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.. */
[84b045d]422                imcb_log( ic, "Could not retrieve vCard of %s", s ? s : "(NULL)" );
[1991be6]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       
[84b045d]530        imcb_log( ic, "%s", reply->str );
[1991be6]531        g_string_free( reply, TRUE );
532       
533        return XT_HANDLED;
534}
535
[a73e91a]536static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
537
[0da65d5]538int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name )
[cfbb3a6]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 );
[47d3ac4]551        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
[cfbb3a6]552        node = jabber_make_packet( "iq", "set", NULL, node );
[a73e91a]553        jabber_cache_add( ic, node, jabber_add_to_roster_callback );
[cfbb3a6]554       
[0da65d5]555        st = jabber_write_packet( ic, node );
[cfbb3a6]556       
557        return st;
558}
559
[a73e91a]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
[0da65d5]583int jabber_remove_from_roster( struct im_connection *ic, char *handle )
[cfbb3a6]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 );
[47d3ac4]595        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
[cfbb3a6]596        node = jabber_make_packet( "iq", "set", NULL, node );
597       
[0da65d5]598        st = jabber_write_packet( ic, node );
[cfbb3a6]599       
600        xt_free_node( node );
601        return st;
602}
[dc0ba9c]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, "Couldnt find the man: %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        }
629
630        jabber_cache_add( ic, query, jabber_iq_parse_features );
631
632        return jabber_write_packet( ic, query );
633}
634
635xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
636{
637        struct xt_node *c;
638        struct jabber_buddy *bud;
639        char *feature;
640
641        if( !( c = xt_find_node( node->children, "query" ) ) ||
642            !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) )
643        {
644                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
645                return XT_HANDLED;
646        }
647        if( ( bud = jabber_buddy_by_jid( ic, xt_find_attr( node, "from") , 0 ) ) == NULL )
648        {
649                /* Who cares about the unknown... */
650                imcb_log( ic, "Couldnt find the man: %s", xt_find_attr( node, "from"));
651                return 0;
652        }
653       
654        c = c->children;
655        while( ( c = xt_find_node( c, "feature" ) ) ) {
656                feature = xt_find_attr( c, "var" );
657                bud->features = g_slist_append(bud->features, g_strdup(feature) );
658                c = c->next;
659        }
660
661        return XT_HANDLED;
662}
663
664xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
665
666xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
667{
668        struct xt_node *node, *query;
669        struct jabber_data *jd = ic->proto_data;
670       
671        node = xt_new_node( "query", NULL, NULL );
672        xt_add_attr( node, "xmlns", xmlns );
673       
674        if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
675        {
676                imcb_log( ic, "WARNING: Couldn't generate server query" );
677                xt_free_node( node );
678        }
679
680        jd->have_streamhosts--;
681        jabber_cache_add( ic, query, jabber_iq_parse_server_features );
682
683        return jabber_write_packet( ic, query );
684}
685
686/*
687 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
688 */
689xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
690{
691        struct xt_node *c;
692        struct jabber_data *jd = ic->proto_data;
693
694        if( !( c = xt_find_node( node->children, "query" ) ) ||
695            !xt_find_attr( node, "from" ) )
696        {
697                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
698                return XT_HANDLED;
699        }
700
701        jd->have_streamhosts++;
702
703        if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_ITEMS ) == 0 )
704        {
705                char *item, *itemjid;
706
707                /* answer from server */
708       
709                c = c->children;
710                while( ( c = xt_find_node( c, "item" ) ) )
711                {
712                        item = xt_find_attr( c, "name" );
713                        itemjid = xt_find_attr( c, "jid" );
714
715                        jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
716
717                        c = c->next;
718                }
719        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 )
720        {
721                char *category, *type;
722
723                /* answer from potential proxy */
724
725                c = c->children;
726                while( ( c = xt_find_node( c, "identity" ) ) )
727                {
728                        category = xt_find_attr( c, "category" );
729                        type = xt_find_attr( c, "type" );
730
731                        if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
732                            category && ( strcmp( category, "proxy" ) == 0 ) )
733                                jabber_iq_query_server( ic, xt_find_attr( node, "from" ), XMLNS_BYTESTREAMS );
734
735                        c = c->next;
736                }
737        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_BYTESTREAMS ) == 0 )
738        {
739                char *host, *jid;
740                int port;
741
742                /* answer from proxy */
743
744                if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
745                    ( host = xt_find_attr( c, "host" ) ) &&
746                    ( port = atoi( xt_find_attr( c, "port" ) ) ) &&
747                    ( jid = xt_find_attr( c, "jid" ) ) )
748                {
749                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
750                        sh->jid = g_strdup( jid );
751                        sh->host = g_strdup( host );
752                        sprintf( sh->port, "%u", port );
753
754                        imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
755                        jd->streamhosts = g_slist_append( jd->streamhosts, sh );
756                }
757        }
758
759        if( jd->have_streamhosts == 0 )
760                jd->have_streamhosts++;
761        return XT_HANDLED;
762}
Note: See TracBrowser for help on using the repository browser.