source: protocols/jabber/iq.c @ 2288705

Last change on this file since 2288705 was 2288705, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-12-07T21:54:19Z

Merging head.

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