source: protocols/jabber/iq.c @ 08135df

Last change on this file since 08135df was 08135df, checked in by ulim <a.sporto+bee@…>, at 2007-12-04T01:08:43Z

Merged in current devel

Wilmer van der Gaast 2007-12-02 Imported setuid() patch from Simo Leone <simo@archlinux...> with some

Wilmer van der Gaast 2007-12-02 Forgot to return something in jabber_chat_join_failed().
Wilmer van der Gaast 2007-12-02 Merging a change I should've pulled before committing three other changes.
Wilmer van der Gaast 2007-12-02 Added charset checks on incoming msgs (from the IRC side) to prevent possible
Wilmer van der Gaast 2007-12-02 Handling of presence-error packets (only useful for groupchats now), moved
Wilmer van der Gaast 2007-12-02 Defining DEBUG via CFLAGS so that it'll always be there, even when a file
Wilmer van der Gaast 2007-12-02 Removed retarded printf() (ARGH) and moved the event handling handling of
Wilmer van der Gaast 2007-11-29 printf() in daemons considered harmful.
Wilmer van der Gaast 2007-11-28 Fixed the epoll+ForkDaemon combination. The libevent event handling

  • Property mode set to 100644
File size: 17.5 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        {
52                if( !( c = xt_find_node( node->children, "query" ) ) ||
53                    !( s = xt_find_attr( c, "xmlns" ) ) )
54                {
[84b045d]55                        imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type );
[58b5f62]56                        return XT_HANDLED;
57                }
58               
59                reply = xt_new_node( "query", NULL, NULL );
60                xt_add_attr( reply, "xmlns", s );
61               
62                /* Of course this is a very essential query to support. ;-) */
[47d3ac4]63                if( strcmp( s, XMLNS_VERSION ) == 0 )
[58b5f62]64                {
65                        xt_add_child( reply, xt_new_node( "name", "BitlBee", NULL ) );
66                        xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) );
67                        xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) );
68                }
[47d3ac4]69                else if( strcmp( s, XMLNS_TIME ) == 0 )
[a4effbf]70                {
71                        time_t time_ep;
72                        char buf[1024];
73                       
74                        buf[sizeof(buf)-1] = 0;
75                        time_ep = time( NULL );
76                       
77                        strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%S", gmtime( &time_ep ) );
78                        xt_add_child( reply, xt_new_node( "utc", buf, NULL ) );
79                       
80                        strftime( buf, sizeof( buf ) - 1, "%Z", localtime( &time_ep ) );
81                        xt_add_child( reply, xt_new_node( "tz", buf, NULL ) );
82                }
[47d3ac4]83                else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
[58b5f62]84                {
[40ef702]85                        const char *features[] = { XMLNS_VERSION,
86                                                   XMLNS_TIME,
87                                                   XMLNS_CHATSTATES,
88                                                   XMLNS_MUC,
[2c2df7d]89                                                   XMLNS_SI,
90                                                   XMLNS_BYTESTREAMS,
91                                                   XMLNS_FILETRANSFER,
[40ef702]92                                                   NULL };
93                        const char **f;
94                       
[58b5f62]95                        c = xt_new_node( "identity", NULL, NULL );
96                        xt_add_attr( c, "category", "client" );
97                        xt_add_attr( c, "type", "pc" );
98                        xt_add_attr( c, "name", "BitlBee" );
99                        xt_add_child( reply, c );
100                       
[40ef702]101                        for( f = features; *f; f ++ )
102                        {
103                                c = xt_new_node( "feature", NULL, NULL );
104                                xt_add_attr( c, "var", *f );
105                                xt_add_child( reply, c );
106                        }
[58b5f62]107                }
108                else
109                {
110                        xt_free_node( reply );
[2c2df7d]111                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
[259edd4]112                        pack = 0;
[58b5f62]113                }
[259edd4]114        }
115        else if( strcmp( type, "set" ) == 0 )
116        {
[2c2df7d]117                if(  ( c = xt_find_node( node->children, "si" ) ) &&
118                     ( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) )
119                {
120                        return jabber_si_handle_request( ic, node, c );
121                } else if( !( c = xt_find_node( node->children, "query" ) ) ||
[dfa41a4]122                    !( s = xt_find_attr( c, "xmlns" ) ) )
123                {
[84b045d]124                        imcb_log( ic, "WARNING: Received incomplete IQ-%s packet", type );
[dfa41a4]125                        return XT_HANDLED;
[2c2df7d]126                } else if( strcmp( s, XMLNS_ROSTER ) == 0 )
127                {
[9bcbe48]128                /* This is a roster push. XMPP servers send this when someone
129                   was added to (or removed from) the buddy list. AFAIK they're
130                   sent even if we added this buddy in our own session. */
[0da65d5]131                        int bare_len = strlen( ic->acc->user );
[abbd8ed]132                       
133                        if( ( s = xt_find_attr( node, "from" ) ) == NULL ||
[0da65d5]134                            ( strncmp( s, ic->acc->user, bare_len ) == 0 &&
[abbd8ed]135                              ( s[bare_len] == 0 || s[bare_len] == '/' ) ) )
136                        {
[0da65d5]137                                jabber_parse_roster( ic, node, NULL );
[abbd8ed]138                               
139                                /* Should we generate a reply here? Don't think it's
140                                   very important... */
141                        }
142                        else
143                        {
[84b045d]144                                imcb_log( ic, "WARNING: %s tried to fake a roster push!", s ? s : "(unknown)" );
[abbd8ed]145                               
146                                xt_free_node( reply );
[2c2df7d]147                                reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
[abbd8ed]148                                pack = 0;
149                        }
[2c2df7d]150                } else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 )
151                {
152                        /* Bytestream Request (stage 2 of file transfer) */
[2ff2076]153                        return jabber_bs_recv_request( ic, node, c );
[2c2df7d]154                } else
[dfa41a4]155                {
156                        xt_free_node( reply );
[2c2df7d]157                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
[dfa41a4]158                        pack = 0;
159                }
[259edd4]160        }
161       
162        /* If we recognized the xmlns and managed to generate a reply,
163           finish and send it. */
164        if( reply )
165        {
166                /* Normally we still have to pack it into an iq-result
167                   packet, but for errors, for example, we don't. */
168                if( pack )
[58b5f62]169                {
170                        reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), reply );
171                        if( ( s = xt_find_attr( node, "id" ) ) )
172                                xt_add_attr( reply, "id", s );
173                }
[259edd4]174               
[0da65d5]175                st = jabber_write_packet( ic, reply );
[259edd4]176                xt_free_node( reply );
177                if( !st )
178                        return XT_ABORT;
[58b5f62]179        }
[70f6aab8]180       
[861c199]181        return XT_HANDLED;
182}
183
[0da65d5]184static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
185static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
[861c199]186
[0da65d5]187int jabber_init_iq_auth( struct im_connection *ic )
[861c199]188{
[0da65d5]189        struct jabber_data *jd = ic->proto_data;
[861c199]190        struct xt_node *node;
191        int st;
[fe7a554]192       
[861c199]193        node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) );
[47d3ac4]194        xt_add_attr( node, "xmlns", XMLNS_AUTH );
[861c199]195        node = jabber_make_packet( "iq", "get", NULL, node );
196       
[0da65d5]197        jabber_cache_add( ic, node, jabber_do_iq_auth );
198        st = jabber_write_packet( ic, node );
[861c199]199       
200        return st;
201}
202
[0da65d5]203static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[861c199]204{
[0da65d5]205        struct jabber_data *jd = ic->proto_data;
[861c199]206        struct xt_node *reply, *query;
207        xt_status st;
208        char *s;
209       
[9bcbe48]210        if( !( query = xt_find_node( node->children, "query" ) ) )
211        {
[84b045d]212                imcb_log( ic, "WARNING: Received incomplete IQ packet while authenticating" );
[c2fb3809]213                imc_logout( ic, FALSE );
[9bcbe48]214                return XT_HANDLED;
215        }
[861c199]216       
217        /* Time to authenticate ourselves! */
218        reply = xt_new_node( "query", NULL, NULL );
[47d3ac4]219        xt_add_attr( reply, "xmlns", XMLNS_AUTH );
[861c199]220        xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) );
[0da65d5]221        xt_add_child( reply, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) );
[861c199]222       
223        if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) )
[21167d2]224        {
[861c199]225                /* We can do digest authentication, it seems, and of
226                   course we prefer that. */
[77bfd07]227                sha1_state_t sha;
[e727608]228                char hash_hex[41];
[861c199]229                unsigned char hash[20];
230                int i;
[21167d2]231               
[77bfd07]232                sha1_init( &sha );
233                sha1_append( &sha, (unsigned char*) s, strlen( s ) );
234                sha1_append( &sha, (unsigned char*) ic->acc->pass, strlen( ic->acc->pass ) );
235                sha1_finish( &sha, hash );
[21167d2]236               
[861c199]237                for( i = 0; i < 20; i ++ )
238                        sprintf( hash_hex + i * 2, "%02x", hash[i] );
[21167d2]239               
[861c199]240                xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) );
[21167d2]241        }
[861c199]242        else if( xt_find_node( query->children, "password" ) )
[0b4a0db]243        {
[861c199]244                /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */
[0da65d5]245                xt_add_child( reply, xt_new_node( "password", ic->acc->pass, NULL ) );
[0b4a0db]246        }
[861c199]247        else
[70f6aab8]248        {
[861c199]249                xt_free_node( reply );
[995913b]250               
[84b045d]251                imcb_error( ic, "Can't find suitable authentication method" );
[c2fb3809]252                imc_logout( ic, FALSE );
[861c199]253                return XT_ABORT;
[70f6aab8]254        }
[861c199]255       
256        reply = jabber_make_packet( "iq", "set", NULL, reply );
[0da65d5]257        jabber_cache_add( ic, reply, jabber_finish_iq_auth );
258        st = jabber_write_packet( ic, reply );
[861c199]259       
260        return st ? XT_HANDLED : XT_ABORT;
261}
262
[0da65d5]263static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[861c199]264{
[0da65d5]265        struct jabber_data *jd = ic->proto_data;
[9bcbe48]266        char *type;
267       
268        if( !( type = xt_find_attr( node, "type" ) ) )
269        {
[84b045d]270                imcb_log( ic, "WARNING: Received incomplete IQ packet while authenticating" );
[c2fb3809]271                imc_logout( ic, FALSE );
[9bcbe48]272                return XT_HANDLED;
273        }
[861c199]274       
275        if( strcmp( type, "error" ) == 0 )
[70f6aab8]276        {
[84b045d]277                imcb_error( ic, "Authentication failure" );
[c2fb3809]278                imc_logout( ic, FALSE );
[861c199]279                return XT_ABORT;
280        }
281        else if( strcmp( type, "result" ) == 0 )
282        {
283                /* This happens when we just successfully authenticated the
284                   old (non-SASL) way. */
285                jd->flags |= JFLAG_AUTHENTICATED;
[0da65d5]286                if( !jabber_get_roster( ic ) )
[70f6aab8]287                        return XT_ABORT;
288        }
[f06894d]289       
290        return XT_HANDLED;
291}
292
[0da65d5]293xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[21167d2]294{
[0da65d5]295        struct jabber_data *jd = ic->proto_data;
[861c199]296        struct xt_node *c;
297        char *s;
[21167d2]298       
[861c199]299        if( ( c = xt_find_node( node->children, "bind" ) ) )
300        {
301                c = xt_find_node( c->children, "jid" );
302                if( c && c->text_len && ( s = strchr( c->text, '/' ) ) &&
[0da65d5]303                    strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 )
[84b045d]304                        imcb_log( ic, "Server changed session resource string to `%s'", s + 1 );
[861c199]305               
306                jd->flags &= ~JFLAG_WAIT_BIND;
307        }
308        else
309        {
310                jd->flags &= ~JFLAG_WAIT_SESSION;
311        }
[21167d2]312       
[861c199]313        if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
314        {
[0da65d5]315                if( !jabber_get_roster( ic ) )
[861c199]316                        return XT_ABORT;
317        }
[21167d2]318       
[861c199]319        return XT_HANDLED;
[21167d2]320}
[70f6aab8]321
[0da65d5]322int jabber_get_roster( struct im_connection *ic )
[70f6aab8]323{
324        struct xt_node *node;
325        int st;
326       
[84b045d]327        imcb_log( ic, "Authenticated, requesting buddy list" );
[70f6aab8]328       
329        node = xt_new_node( "query", NULL, NULL );
[47d3ac4]330        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
[70f6aab8]331        node = jabber_make_packet( "iq", "get", NULL, node );
332       
[0da65d5]333        jabber_cache_add( ic, node, jabber_parse_roster );
334        st = jabber_write_packet( ic, node );
[70f6aab8]335       
336        return st;
337}
[cfbb3a6]338
[0da65d5]339static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[861c199]340{
341        struct xt_node *query, *c;
[abbd8ed]342        int initial = ( orig != NULL );
[861c199]343       
[9bcbe48]344        if( !( query = xt_find_node( node->children, "query" ) ) )
345        {
[84b045d]346                imcb_log( ic, "WARNING: Received NULL roster packet" );
[9bcbe48]347                return XT_HANDLED;
348        }
[861c199]349       
350        c = query->children;
351        while( ( c = xt_find_node( c, "item" ) ) )
352        {
[f0cb961]353                struct xt_node *group = xt_find_node( node->children, "group" );
[861c199]354                char *jid = xt_find_attr( c, "jid" );
355                char *name = xt_find_attr( c, "name" );
356                char *sub = xt_find_attr( c, "subscription" );
357               
[f0cb961]358                if( jid && sub )
[abbd8ed]359                {
360                        if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
361                        {
[f0cb961]362                                if( initial || imcb_find_buddy( ic, jid ) == NULL )
363                                        imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
364                                                                   group->text : NULL );
365                               
[d06eabf]366                                if( name )
367                                        imcb_rename_buddy( ic, jid, name );
[abbd8ed]368                        }
369                        else if( strcmp( sub, "remove" ) == 0 )
370                        {
[0da65d5]371                                jabber_buddy_remove_bare( ic, jid );
[998b103]372                                imcb_remove_buddy( ic, jid, NULL );
[abbd8ed]373                        }
374                }
[861c199]375               
376                c = c->next;
377        }
378       
[abbd8ed]379        if( initial )
[84b045d]380                imcb_connected( ic );
[861c199]381       
382        return XT_HANDLED;
383}
384
[0da65d5]385int jabber_get_vcard( struct im_connection *ic, char *bare_jid )
[1991be6]386{
387        struct xt_node *node;
388       
389        if( strchr( bare_jid, '/' ) )
390                return 1;       /* This was an error, but return 0 should only be done if the connection died... */
391       
392        node = xt_new_node( "vCard", NULL, NULL );
[47d3ac4]393        xt_add_attr( node, "xmlns", XMLNS_VCARD );
[1991be6]394        node = jabber_make_packet( "iq", "get", bare_jid, node );
395       
[0da65d5]396        jabber_cache_add( ic, node, jabber_iq_display_vcard );
397        return jabber_write_packet( ic, node );
[1991be6]398}
399
[0da65d5]400static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
[1991be6]401{
[0da65d5]402        struct xt_node *vc, *c, *sc; /* subchild, ic is already in use ;-) */
[1991be6]403        GString *reply;
404        char *s;
405       
406        if( ( s = xt_find_attr( node, "type" ) ) == NULL ||
407            strcmp( s, "result" ) != 0 ||
408            ( vc = xt_find_node( node->children, "vCard" ) ) == NULL )
409        {
410                s = xt_find_attr( orig, "to" ); /* If this returns NULL something's wrong.. */
[84b045d]411                imcb_log( ic, "Could not retrieve vCard of %s", s ? s : "(NULL)" );
[1991be6]412                return XT_HANDLED;
413        }
414       
415        s = xt_find_attr( orig, "to" );
416        reply = g_string_new( "vCard information for " );
417        reply = g_string_append( reply, s ? s : "(NULL)" );
418        reply = g_string_append( reply, ":\n" );
419       
420        /* I hate this format, I really do... */
421       
422        if( ( c = xt_find_node( vc->children, "FN" ) ) && c->text_len )
423                g_string_append_printf( reply, "Name: %s\n", c->text );
424       
425        if( ( c = xt_find_node( vc->children, "N" ) ) && c->children )
426        {
427                reply = g_string_append( reply, "Full name:" );
428               
429                if( ( sc = xt_find_node( c->children, "PREFIX" ) ) && sc->text_len )
430                        g_string_append_printf( reply, " %s", sc->text );
431                if( ( sc = xt_find_node( c->children, "GIVEN" ) ) && sc->text_len )
432                        g_string_append_printf( reply, " %s", sc->text );
433                if( ( sc = xt_find_node( c->children, "MIDDLE" ) ) && sc->text_len )
434                        g_string_append_printf( reply, " %s", sc->text );
435                if( ( sc = xt_find_node( c->children, "FAMILY" ) ) && sc->text_len )
436                        g_string_append_printf( reply, " %s", sc->text );
437                if( ( sc = xt_find_node( c->children, "SUFFIX" ) ) && sc->text_len )
438                        g_string_append_printf( reply, " %s", sc->text );
439               
440                reply = g_string_append_c( reply, '\n' );
441        }
442       
443        if( ( c = xt_find_node( vc->children, "NICKNAME" ) ) && c->text_len )
444                g_string_append_printf( reply, "Nickname: %s\n", c->text );
445       
446        if( ( c = xt_find_node( vc->children, "BDAY" ) ) && c->text_len )
447                g_string_append_printf( reply, "Date of birth: %s\n", c->text );
448       
449        /* Slightly alternative use of for... ;-) */
450        for( c = vc->children; ( c = xt_find_node( c, "EMAIL" ) ); c = c->next )
451        {
452                if( ( sc = xt_find_node( c->children, "USERID" ) ) == NULL || sc->text_len == 0 )
453                        continue;
454               
455                if( xt_find_node( c->children, "HOME" ) )
456                        s = "Home";
457                else if( xt_find_node( c->children, "WORK" ) )
458                        s = "Work";
459                else
460                        s = "Misc.";
461               
462                g_string_append_printf( reply, "%s e-mail address: %s\n", s, sc->text );
463        }
464       
465        if( ( c = xt_find_node( vc->children, "URL" ) ) && c->text_len )
466                g_string_append_printf( reply, "Homepage: %s\n", c->text );
467       
468        /* Slightly alternative use of for... ;-) */
469        for( c = vc->children; ( c = xt_find_node( c, "ADR" ) ); c = c->next )
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 address: ", s );
479               
480                if( ( sc = xt_find_node( c->children, "STREET" ) ) && sc->text_len )
481                        g_string_append_printf( reply, "%s ", sc->text );
482                if( ( sc = xt_find_node( c->children, "EXTADR" ) ) && sc->text_len )
483                        g_string_append_printf( reply, "%s, ", sc->text );
484                if( ( sc = xt_find_node( c->children, "PCODE" ) ) && sc->text_len )
485                        g_string_append_printf( reply, "%s, ", sc->text );
486                if( ( sc = xt_find_node( c->children, "LOCALITY" ) ) && sc->text_len )
487                        g_string_append_printf( reply, "%s, ", sc->text );
488                if( ( sc = xt_find_node( c->children, "REGION" ) ) && sc->text_len )
489                        g_string_append_printf( reply, "%s, ", sc->text );
490                if( ( sc = xt_find_node( c->children, "CTRY" ) ) && sc->text_len )
491                        g_string_append_printf( reply, "%s", sc->text );
492               
493                if( reply->str[reply->len-2] == ',' )
494                        reply = g_string_truncate( reply, reply->len-2 );
495               
496                reply = g_string_append_c( reply, '\n' );
497        }
498       
499        for( c = vc->children; ( c = xt_find_node( c, "TEL" ) ); c = c->next )
500        {
501                if( ( sc = xt_find_node( c->children, "NUMBER" ) ) == NULL || sc->text_len == 0 )
502                        continue;
503               
504                if( xt_find_node( c->children, "HOME" ) )
505                        s = "Home";
506                else if( xt_find_node( c->children, "WORK" ) )
507                        s = "Work";
508                else
509                        s = "Misc.";
510               
511                g_string_append_printf( reply, "%s phone number: %s\n", s, sc->text );
512        }
513       
514        if( ( c = xt_find_node( vc->children, "DESC" ) ) && c->text_len )
515                g_string_append_printf( reply, "Other information:\n%s", c->text );
516       
517        /* *sigh* */
518       
[84b045d]519        imcb_log( ic, "%s", reply->str );
[1991be6]520        g_string_free( reply, TRUE );
521       
522        return XT_HANDLED;
523}
524
[0da65d5]525int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name )
[cfbb3a6]526{
527        struct xt_node *node;
528        int st;
529       
530        /* Build the item entry */
531        node = xt_new_node( "item", NULL, NULL );
532        xt_add_attr( node, "jid", handle );
533        if( name )
534                xt_add_attr( node, "name", name );
535       
536        /* And pack it into a roster-add packet */
537        node = xt_new_node( "query", NULL, node );
[47d3ac4]538        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
[cfbb3a6]539        node = jabber_make_packet( "iq", "set", NULL, node );
540       
[0da65d5]541        st = jabber_write_packet( ic, node );
[cfbb3a6]542       
543        xt_free_node( node );
544        return st;
545}
546
[0da65d5]547int jabber_remove_from_roster( struct im_connection *ic, char *handle )
[cfbb3a6]548{
549        struct xt_node *node;
550        int st;
551       
552        /* Build the item entry */
553        node = xt_new_node( "item", NULL, NULL );
554        xt_add_attr( node, "jid", handle );
555        xt_add_attr( node, "subscription", "remove" );
556       
557        /* And pack it into a roster-add packet */
558        node = xt_new_node( "query", NULL, node );
[47d3ac4]559        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
[cfbb3a6]560        node = jabber_make_packet( "iq", "set", NULL, node );
561       
[0da65d5]562        st = jabber_write_packet( ic, node );
[cfbb3a6]563       
564        xt_free_node( node );
565        return st;
566}
Note: See TracBrowser for help on using the repository browser.