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

Last change on this file since 1ba7e8f was 1ba7e8f, checked in by ulim <a.sporto+bee@…>, at 2008-02-15T17:38:57Z

Merged with upstream r328

Wilmer van der Gaast 2008-02-11 Got rid of some noise at startup: complaining when the default configuration

Wilmer van der Gaast 2008-02-10 Added support for password-protected Jabber chatrooms.
Wilmer van der Gaast 2008-02-10 Making AI_ADDRCONFIG optional, it doesn't exist on at least NetBSD and
Wilmer van der Gaast 2008-02-09 Restored "add -tmp". A bit hackish, but it will do for now.
Wilmer van der Gaast 2008-02-07 Fixed getnameinfo() calls, this fixes Solaris stability issues. Thanks to
Wilmer van der Gaast 2008-02-04 Added bogus G_GNUC_MALLOC to restore GLib 2.4 compatibility (hopefully).
Wilmer van der Gaast 2008-02-03 Messages from the user are also included in backlogs when joining a Jabber
Wilmer van der Gaast 2008-02-03 Disabling "Unknown command" warnings since they're very noisy and pretty
Wilmer van der Gaast 2008-02-03 Implemented XEP-0115. This adds some info to the <presence/> tags so
Wilmer van der Gaast 2008-02-03 Saner garbage collection of cached packets in the Jabber module. Now
Wilmer van der Gaast 2008-02-02 Added help_free() and cleaned up some very stale help-related stuff I
Wilmer van der Gaast 2008-01-30 Fixed handling of OSCAR multi-part messages... They're not arrays, they're
Wilmer van der Gaast 2008-01-24 Keeping track of valid Jabber connections so _connected() events will be
Wilmer van der Gaast 2008-01-24 Fixed two valgrind warnings (partially uninitialized "struct tm" vars.)
Wilmer van der Gaast 2008-01-20 The Jabber module now uses imcb_chat_log() instead of imcb_log() where
Wilmer van der Gaast 2008-01-20 Added imcb_chat_log() for chatroom system messages, so they can be
Wilmer van der Gaast 2008-01-20 GET_BUDDY_FIRST wasn't actually implemented, even though it was in use
Wilmer van der Gaast 2008-01-19 Using test -f instead of test -e. This breaks if the include files are
Wilmer van der Gaast 2008-01-19 Added byte swapping code to the new MD5 checksumming code to make it work
Wilmer van der Gaast 2008-01-18 Moving imcb_chat_new() to a saner location (no code changes) and fixing
Wilmer van der Gaast 2008-01-17 Apparently ext_yahoo_got_im can be called with msg=NULL, so it should be
Wilmer van der Gaast 2008-01-17 Fixing some Solaris compiler warnings (u_int->uint, adding some typecasts
Wilmer van der Gaast 2008-01-13 Fixed handing of failed groupchat joins.
Wilmer van der Gaast 2008-01-13 Fixed "Conditional jump or move depends on uninitialised value(s)" at
Wilmer van der Gaast 2008-01-13 Fixed quickstart2. (Bug #349.)
Wilmer van der Gaast 2008-01-13 Different handling of charset mismatches before login time. Ignoring a
Wilmer van der Gaast 2008-01-12 When a switchboard connection dies (at the TCP level) and there are still
Wilmer van der Gaast 2008-01-12 Killed info_string_append() and now showing the IP address of ICQ users
Wilmer van der Gaast 2008-01-11 Fixing bug #344, now away states should always be correct, even when people
Wilmer van der Gaast 2008-01-11 Adding own handle to protocol name in blist output for people with multiple
Wilmer van der Gaast 2008-01-10 Now setting odata->icq properly again, this got lost some time ago, which
Wilmer van der Gaast 2008-01-06 More consistency in error/warning errors. Until now "WARNING:" was usually
Wilmer van der Gaast 2008-01-06 Changed warning message about unsent MSN messages. It should show the actual
Wilmer van der Gaast 2008-01-05 Added "mail_notifications" setting. Who needs those notifications anyway?
Wilmer van der Gaast 2008-01-05 Build fix from vmiklos.
Wilmer van der Gaast 2008-01-05 Added handling of MSN switchboard NAK messages. Untested, but hey, it
Wilmer van der Gaast 2008-01-05 Removed closure->result. I was planning to add some more stuff, but will
Miklos Vajna 2007-12-31 encode: md5.c is no longer in protocols/, it's in lib/
Wilmer van der Gaast 2007-12-28 Fixed return value check in proxy_connect(), since on some systems
Wilmer van der Gaast 2007-12-28 Added missing return in jabber_login().
Wilmer van der Gaast 2007-12-16 Implemented XEP-0199 (patch from misc@…).
Wilmer van der Gaast 2007-12-12 Checking conn->xcred before trying to clean it up since GnuTLS doesn't
Wilmer van der Gaast 2007-12-12 Killed the <server> parameter to "account add" and changed the default
Wilmer van der Gaast 2007-12-12 Fixed sockerr_again() usage in Jabber module to (hopefully) fix a 100% CPU
Wilmer van der Gaast 2007-12-10 Don't allow nicks that start with a number.
Wilmer van der Gaast 2007-12-10 Fixed "set xxx" syntax (it showed all settings instead of just xxx).
Wilmer van der Gaast 2007-12-09 If I keep forgetting to credit people in commit msgs I should probably add
Wilmer van der Gaast 2007-12-09 Added /invite support for Jabber chatrooms (and fixed the argument order

  • Property mode set to 100644
File size: 22.3 KB
Line 
1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - IQ packets                                               *
5*                                                                           *
6*  Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net>                   *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include "jabber.h"
25#include "sha1.h"
26
27static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
28static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
29
30xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
31{
32        struct im_connection *ic = data;
33        struct xt_node *c, *reply = NULL;
34        char *type, *s;
35        int st, pack = 1;
36       
37        type = xt_find_attr( node, "type" );
38       
39        if( !type )
40        {
41                imcb_error( ic, "Received IQ packet without type." );
42                imc_logout( ic, TRUE );
43                return XT_ABORT;
44        }
45       
46        if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 )
47        {
48                return jabber_cache_handle_packet( ic, node );
49        }
50        else if( strcmp( type, "get" ) == 0 )
51        {
52                if( !( ( c = xt_find_node( node->children, "query" ) ) ||
53                       ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just <query/> ????? */
54                    !( s = xt_find_attr( c, "xmlns" ) ) )
55                {
56                        imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
57                        return XT_HANDLED;
58                }
59               
60                reply = xt_new_node( "query", NULL, NULL );
61                xt_add_attr( reply, "xmlns", s );
62               
63                /* Of course this is a very essential query to support. ;-) */
64                if( strcmp( s, XMLNS_VERSION ) == 0 )
65                {
66                        xt_add_child( reply, xt_new_node( "name", "BitlBee", NULL ) );
67                        xt_add_child( reply, xt_new_node( "version", BITLBEE_VERSION, NULL ) );
68                        xt_add_child( reply, xt_new_node( "os", ARCH, NULL ) );
69                }
70                else if( strcmp( s, XMLNS_TIME ) == 0 )
71                {
72                        time_t time_ep;
73                        char buf[1024];
74                       
75                        buf[sizeof(buf)-1] = 0;
76                        time_ep = time( NULL );
77                       
78                        strftime( buf, sizeof( buf ) - 1, "%Y%m%dT%H:%M:%S", gmtime( &time_ep ) );
79                        xt_add_child( reply, xt_new_node( "utc", buf, NULL ) );
80                       
81                        strftime( buf, sizeof( buf ) - 1, "%Z", localtime( &time_ep ) );
82                        xt_add_child( reply, xt_new_node( "tz", buf, NULL ) );
83                }
84                else if( strcmp( s, XMLNS_PING ) == 0 )
85                {
86                        xt_free_node( reply );
87                        reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), NULL );
88                        if( ( s = xt_find_attr( node, "id" ) ) )
89                                xt_add_attr( reply, "id", s );
90                        pack = 0;
91                }
92                else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
93                {
94                        const char *features[] = { XMLNS_DISCO_INFO,
95                                                   XMLNS_VERSION,
96                                                   XMLNS_TIME,
97                                                   XMLNS_CHATSTATES,
98                                                   XMLNS_MUC,
99                                                   XMLNS_PING,
100                                                   XMLNS_SI,
101                                                   XMLNS_BYTESTREAMS,
102                                                   XMLNS_FILETRANSFER,
103                                                   NULL };
104                        const char **f;
105                       
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                       
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                        }
118                }
119                else
120                {
121                        xt_free_node( reply );
122                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
123                        pack = 0;
124                }
125        }
126        else if( strcmp( type, "set" ) == 0 )
127        {
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" ) ) ||
133                    !( s = xt_find_attr( c, "xmlns" ) ) )
134                {
135                        imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
136                        return XT_HANDLED;
137                } else if( strcmp( s, XMLNS_ROSTER ) == 0 )
138                {
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. */
142                        int bare_len = strlen( ic->acc->user );
143                       
144                        if( ( s = xt_find_attr( node, "from" ) ) == NULL ||
145                            ( strncmp( s, ic->acc->user, bare_len ) == 0 &&
146                              ( s[bare_len] == 0 || s[bare_len] == '/' ) ) )
147                        {
148                                jabber_parse_roster( ic, node, NULL );
149                               
150                                /* Should we generate a reply here? Don't think it's
151                                   very important... */
152                        }
153                        else
154                        {
155                                imcb_log( ic, "Warning: %s tried to fake a roster push!", s ? s : "(unknown)" );
156                               
157                                xt_free_node( reply );
158                                reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
159                                pack = 0;
160                        }
161                } else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 )
162                {
163                        /* Bytestream Request (stage 2 of file transfer) */
164                        return jabber_bs_recv_request( ic, node, c );
165                } else
166                {
167                        xt_free_node( reply );
168                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
169                        pack = 0;
170                }
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 )
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                }
185               
186                st = jabber_write_packet( ic, reply );
187                xt_free_node( reply );
188                if( !st )
189                        return XT_ABORT;
190        }
191       
192        return XT_HANDLED;
193}
194
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 );
197
198int jabber_init_iq_auth( struct im_connection *ic )
199{
200        struct jabber_data *jd = ic->proto_data;
201        struct xt_node *node;
202        int st;
203       
204        node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) );
205        xt_add_attr( node, "xmlns", XMLNS_AUTH );
206        node = jabber_make_packet( "iq", "get", NULL, node );
207       
208        jabber_cache_add( ic, node, jabber_do_iq_auth );
209        st = jabber_write_packet( ic, node );
210       
211        return st;
212}
213
214static xt_status jabber_do_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
215{
216        struct jabber_data *jd = ic->proto_data;
217        struct xt_node *reply, *query;
218        xt_status st;
219        char *s;
220       
221        if( !( query = xt_find_node( node->children, "query" ) ) )
222        {
223                imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" );
224                imc_logout( ic, FALSE );
225                return XT_HANDLED;
226        }
227       
228        /* Time to authenticate ourselves! */
229        reply = xt_new_node( "query", NULL, NULL );
230        xt_add_attr( reply, "xmlns", XMLNS_AUTH );
231        xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) );
232        xt_add_child( reply, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) );
233       
234        if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) )
235        {
236                /* We can do digest authentication, it seems, and of
237                   course we prefer that. */
238                sha1_state_t sha;
239                char hash_hex[41];
240                unsigned char hash[20];
241                int i;
242               
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 );
247               
248                for( i = 0; i < 20; i ++ )
249                        sprintf( hash_hex + i * 2, "%02x", hash[i] );
250               
251                xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) );
252        }
253        else if( xt_find_node( query->children, "password" ) )
254        {
255                /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */
256                xt_add_child( reply, xt_new_node( "password", ic->acc->pass, NULL ) );
257        }
258        else
259        {
260                xt_free_node( reply );
261               
262                imcb_error( ic, "Can't find suitable authentication method" );
263                imc_logout( ic, FALSE );
264                return XT_ABORT;
265        }
266       
267        reply = jabber_make_packet( "iq", "set", NULL, reply );
268        jabber_cache_add( ic, reply, jabber_finish_iq_auth );
269        st = jabber_write_packet( ic, reply );
270       
271        return st ? XT_HANDLED : XT_ABORT;
272}
273
274static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
275{
276        struct jabber_data *jd = ic->proto_data;
277        char *type;
278       
279        if( !( type = xt_find_attr( node, "type" ) ) )
280        {
281                imcb_log( ic, "Warning: Received incomplete IQ packet while authenticating" );
282                imc_logout( ic, FALSE );
283                return XT_HANDLED;
284        }
285       
286        if( strcmp( type, "error" ) == 0 )
287        {
288                imcb_error( ic, "Authentication failure" );
289                imc_logout( ic, FALSE );
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;
297                if( !jabber_get_roster( ic ) )
298                        return XT_ABORT;
299        }
300       
301        return XT_HANDLED;
302}
303
304xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
305{
306        struct jabber_data *jd = ic->proto_data;
307        struct xt_node *c;
308        char *s;
309       
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, '/' ) ) &&
314                    strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 )
315                        imcb_log( ic, "Server changed session resource string to `%s'", s + 1 );
316               
317                jd->flags &= ~JFLAG_WAIT_BIND;
318        }
319        else
320        {
321                jd->flags &= ~JFLAG_WAIT_SESSION;
322        }
323       
324        if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
325        {
326                if( !jabber_get_roster( ic ) )
327                        return XT_ABORT;
328        }
329       
330        return XT_HANDLED;
331}
332
333int jabber_get_roster( struct im_connection *ic )
334{
335        struct xt_node *node;
336        int st;
337       
338        imcb_log( ic, "Authenticated, requesting buddy list" );
339       
340        node = xt_new_node( "query", NULL, NULL );
341        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
342        node = jabber_make_packet( "iq", "get", NULL, node );
343       
344        jabber_cache_add( ic, node, jabber_parse_roster );
345        st = jabber_write_packet( ic, node );
346       
347        return st;
348}
349
350static xt_status jabber_parse_roster( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
351{
352        struct xt_node *query, *c;
353        int initial = ( orig != NULL );
354       
355        if( !( query = xt_find_node( node->children, "query" ) ) )
356        {
357                imcb_log( ic, "Warning: Received NULL roster packet" );
358                return XT_HANDLED;
359        }
360       
361        c = query->children;
362        while( ( c = xt_find_node( c, "item" ) ) )
363        {
364                struct xt_node *group = xt_find_node( node->children, "group" );
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               
369                if( jid && sub )
370                {
371                        if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
372                        {
373                                if( initial || imcb_find_buddy( ic, jid ) == NULL )
374                                        imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
375                                                                   group->text : NULL );
376                               
377                                if( name )
378                                        imcb_rename_buddy( ic, jid, name );
379                        }
380                        else if( strcmp( sub, "remove" ) == 0 )
381                        {
382                                jabber_buddy_remove_bare( ic, jid );
383                                imcb_remove_buddy( ic, jid, NULL );
384                        }
385                }
386               
387                c = c->next;
388        }
389       
390        if( initial )
391                imcb_connected( ic );
392       
393        return XT_HANDLED;
394}
395
396int jabber_get_vcard( struct im_connection *ic, char *bare_jid )
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 );
404        xt_add_attr( node, "xmlns", XMLNS_VCARD );
405        node = jabber_make_packet( "iq", "get", bare_jid, node );
406       
407        jabber_cache_add( ic, node, jabber_iq_display_vcard );
408        return jabber_write_packet( ic, node );
409}
410
411static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
412{
413        struct xt_node *vc, *c, *sc; /* subchild, ic is already in use ;-) */
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.. */
422                imcb_log( ic, "Could not retrieve vCard of %s", s ? s : "(NULL)" );
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       
530        imcb_log( ic, "%s", reply->str );
531        g_string_free( reply, TRUE );
532       
533        return XT_HANDLED;
534}
535
536int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name )
537{
538        struct xt_node *node;
539        int st;
540       
541        /* Build the item entry */
542        node = xt_new_node( "item", NULL, NULL );
543        xt_add_attr( node, "jid", handle );
544        if( name )
545                xt_add_attr( node, "name", name );
546       
547        /* And pack it into a roster-add packet */
548        node = xt_new_node( "query", NULL, node );
549        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
550        node = jabber_make_packet( "iq", "set", NULL, node );
551       
552        st = jabber_write_packet( ic, node );
553       
554        xt_free_node( node );
555        return st;
556}
557
558int jabber_remove_from_roster( struct im_connection *ic, char *handle )
559{
560        struct xt_node *node;
561        int st;
562       
563        /* Build the item entry */
564        node = xt_new_node( "item", NULL, NULL );
565        xt_add_attr( node, "jid", handle );
566        xt_add_attr( node, "subscription", "remove" );
567       
568        /* And pack it into a roster-add packet */
569        node = xt_new_node( "query", NULL, node );
570        xt_add_attr( node, "xmlns", XMLNS_ROSTER );
571        node = jabber_make_packet( "iq", "set", NULL, node );
572       
573        st = jabber_write_packet( ic, node );
574       
575        xt_free_node( node );
576        return st;
577}
578
579xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
580
581xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
582{
583        struct xt_node *node, *query;
584        struct jabber_buddy *bud;
585       
586        if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
587        {
588                /* Who cares about the unknown... */
589                imcb_log( ic, "Couldnt find the man: %s", bare_jid);
590                return 0;
591        }
592       
593        if( bud->features ) /* been here already */
594                return XT_HANDLED;
595       
596        node = xt_new_node( "query", NULL, NULL );
597        xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
598       
599        if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
600        {
601                imcb_log( ic, "WARNING: Couldn't generate feature query" );
602                xt_free_node( node );
603        }
604
605        jabber_cache_add( ic, query, jabber_iq_parse_features );
606
607        return jabber_write_packet( ic, query );
608}
609
610xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
611{
612        struct xt_node *c;
613        struct jabber_buddy *bud;
614        char *feature;
615
616        if( !( c = xt_find_node( node->children, "query" ) ) ||
617            !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) )
618        {
619                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
620                return XT_HANDLED;
621        }
622        if( ( bud = jabber_buddy_by_jid( ic, xt_find_attr( node, "from") , 0 ) ) == NULL )
623        {
624                /* Who cares about the unknown... */
625                imcb_log( ic, "Couldnt find the man: %s", xt_find_attr( node, "from"));
626                return 0;
627        }
628       
629        c = c->children;
630        while( ( c = xt_find_node( c, "feature" ) ) ) {
631                feature = xt_find_attr( c, "var" );
632                bud->features = g_slist_append(bud->features, g_strdup(feature) );
633                c = c->next;
634        }
635
636        return XT_HANDLED;
637}
638
639xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
640
641xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
642{
643        struct xt_node *node, *query;
644        struct jabber_data *jd = ic->proto_data;
645       
646        node = xt_new_node( "query", NULL, NULL );
647        xt_add_attr( node, "xmlns", xmlns );
648       
649        if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
650        {
651                imcb_log( ic, "WARNING: Couldn't generate server query" );
652                xt_free_node( node );
653        }
654
655        jd->have_streamhosts--;
656        jabber_cache_add( ic, query, jabber_iq_parse_server_features );
657
658        return jabber_write_packet( ic, query );
659}
660
661/*
662 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
663 */
664xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
665{
666        struct xt_node *c;
667        struct jabber_data *jd = ic->proto_data;
668
669        if( !( c = xt_find_node( node->children, "query" ) ) ||
670            !xt_find_attr( node, "from" ) )
671        {
672                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
673                return XT_HANDLED;
674        }
675
676        jd->have_streamhosts++;
677
678        if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_ITEMS ) == 0 )
679        {
680                char *item, *itemjid;
681
682                /* answer from server */
683       
684                c = c->children;
685                while( ( c = xt_find_node( c, "item" ) ) )
686                {
687                        item = xt_find_attr( c, "name" );
688                        itemjid = xt_find_attr( c, "jid" );
689
690                        jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
691
692                        c = c->next;
693                }
694        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 )
695        {
696                char *category, *type;
697
698                /* answer from potential proxy */
699
700                c = c->children;
701                while( ( c = xt_find_node( c, "identity" ) ) )
702                {
703                        category = xt_find_attr( c, "category" );
704                        type = xt_find_attr( c, "type" );
705
706                        if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
707                            category && ( strcmp( category, "proxy" ) == 0 ) )
708                                jabber_iq_query_server( ic, xt_find_attr( node, "from" ), XMLNS_BYTESTREAMS );
709
710                        c = c->next;
711                }
712        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_BYTESTREAMS ) == 0 )
713        {
714                char *host, *jid;
715                int port;
716
717                /* answer from proxy */
718
719                if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
720                    ( host = xt_find_attr( c, "host" ) ) &&
721                    ( port = atoi( xt_find_attr( c, "port" ) ) ) &&
722                    ( jid = xt_find_attr( c, "jid" ) ) )
723                {
724                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
725                        sh->jid = g_strdup( jid );
726                        sh->host = g_strdup( host );
727                        sprintf( sh->port, "%u", port );
728
729                        imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
730                        jd->streamhosts = g_slist_append( jd->streamhosts, sh );
731                }
732        }
733
734        if( jd->have_streamhosts == 0 )
735                jd->have_streamhosts++;
736        return XT_HANDLED;
737}
Note: See TracBrowser for help on using the repository browser.