diff options
Diffstat (limited to 'protocols/jabber')
-rw-r--r-- | protocols/jabber/Makefile | 2 | ||||
-rw-r--r-- | protocols/jabber/io.c | 12 | ||||
-rw-r--r-- | protocols/jabber/jabber.c | 55 | ||||
-rw-r--r-- | protocols/jabber/jabber.h | 6 | ||||
-rw-r--r-- | protocols/jabber/jabber_util.c | 67 | ||||
-rw-r--r-- | protocols/jabber/message.c | 17 | ||||
-rw-r--r-- | protocols/jabber/xmltree.c | 589 | ||||
-rw-r--r-- | protocols/jabber/xmltree.h | 97 |
8 files changed, 110 insertions, 735 deletions
diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index 3ce78127..e7a505ba 100644 --- a/protocols/jabber/Makefile +++ b/protocols/jabber/Makefile @@ -9,7 +9,7 @@ -include ../../Makefile.settings # [SH] Program variables -objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o +objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o CFLAGS += -Wall LFLAGS += -r diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 86c216ef..10efad37 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -240,8 +240,13 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition return FALSE; } - /* EAGAIN/etc or a successful read. */ - return TRUE; + if( ssl_pending( jd->ssl ) ) + /* OpenSSL empties the TCP buffers completely but may keep some + data in its internap buffers. select() won't see that, but + ssl_pending() does. */ + return jabber_read_callback( data, fd, cond ); + else + return TRUE; } gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ) @@ -520,8 +525,7 @@ gboolean jabber_start_stream( struct im_connection *ic ) /* We'll start our stream now, so prepare everything to receive one from the server too. */ xt_free( jd->xt ); /* In case we're RE-starting. */ - jd->xt = xt_new( ic ); - jd->xt->handlers = (struct xt_handler_entry*) jabber_handlers; + jd->xt = xt_new( jabber_handlers, ic ); if( jd->r_inpa <= 0 ) jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic ); diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index dac18bae..5fb2c4fc 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -32,15 +32,33 @@ #include "bitlbee.h" #include "jabber.h" #include "md5.h" -#include "base64.h" GSList *jabber_connections; +/* First enty is the default */ +static const int jabber_port_list[] = { + 5222, + 5223, + 5220, + 5221, + 5224, + 5225, + 5226, + 5227, + 5228, + 5229, + 80, + 443, + 0 +}; + static void jabber_init( account_t *acc ) { set_t *s; + char str[16]; - s = set_add( &acc->set, "port", JABBER_PORT_DEFAULT, set_eval_int, acc ); + g_snprintf( str, sizeof( str ), "%d", jabber_port_list[0] ); + s = set_add( &acc->set, "port", str, set_eval_int, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; s = set_add( &acc->set, "priority", "0", set_eval_priority, acc ); @@ -71,6 +89,7 @@ static void jabber_login( account_t *acc ) struct jabber_data *jd = g_new0( struct jabber_data, 1 ); struct ns_srv_reply *srv = NULL; char *connect_to, *s; + int i; /* For now this is needed in the _connected() handlers if using GLib event handling, to make sure we're not handling events @@ -176,11 +195,13 @@ static void jabber_login( account_t *acc ) imcb_log( ic, "Connecting" ); - if( set_getint( &acc->set, "port" ) < JABBER_PORT_MIN || - set_getint( &acc->set, "port" ) > JABBER_PORT_MAX ) + for( i = 0; jabber_port_list[i] > 0; i ++ ) + if( set_getint( &acc->set, "port" ) == jabber_port_list[i] ) + break; + + if( jabber_port_list[i] == 0 ) { - imcb_log( ic, "Incorrect port number, must be in the %d-%d range", - JABBER_PORT_MIN, JABBER_PORT_MAX ); + imcb_log( ic, "Illegal port number" ); imc_logout( ic, FALSE ); return; } @@ -218,24 +239,20 @@ static void jabber_login( account_t *acc ) jabber_generate_id_hash( jd ); } +/* This generates an unfinished md5_state_t variable. Every time we generate + an ID, we finish the state by adding a sequence number and take the hash. */ static void jabber_generate_id_hash( struct jabber_data *jd ) { - md5_state_t id_hash; - md5_byte_t binbuf[16]; + md5_byte_t binbuf[4]; char *s; - md5_init( &id_hash ); - md5_append( &id_hash, (unsigned char *) jd->username, strlen( jd->username ) ); - md5_append( &id_hash, (unsigned char *) jd->server, strlen( jd->server ) ); + md5_init( &jd->cached_id_prefix ); + md5_append( &jd->cached_id_prefix, (unsigned char *) jd->username, strlen( jd->username ) ); + md5_append( &jd->cached_id_prefix, (unsigned char *) jd->server, strlen( jd->server ) ); s = set_getstr( &jd->ic->acc->set, "resource" ); - md5_append( &id_hash, (unsigned char *) s, strlen( s ) ); - random_bytes( binbuf, 16 ); - md5_append( &id_hash, binbuf, 16 ); - md5_finish( &id_hash, binbuf ); - - s = base64_encode( binbuf, 9 ); - jd->cached_id_prefix = g_strdup_printf( "%s%s", JABBER_CACHED_ID, s ); - g_free( s ); + md5_append( &jd->cached_id_prefix, (unsigned char *) s, strlen( s ) ); + random_bytes( binbuf, 4 ); + md5_append( &jd->cached_id_prefix, binbuf, 4 ); } static void jabber_logout( struct im_connection *ic ) diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 1ff0e8dd..904bf0c4 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -85,7 +85,7 @@ struct jabber_data struct jabber_away_state *away_state; char *away_message; - char *cached_id_prefix; + md5_state_t cached_id_prefix; GHashTable *node_cache; GHashTable *buddies; }; @@ -134,10 +134,6 @@ struct jabber_chat #define JABBER_XMLCONSOLE_HANDLE "xmlconsole" -#define JABBER_PORT_DEFAULT "5222" -#define JABBER_PORT_MIN 5220 -#define JABBER_PORT_MAX 5229 - /* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the first one should be used, but when storing a packet in the cache, a "special" kind of ID is assigned to make it easier later to figure out diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 6e872040..1bee5009 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -22,6 +22,8 @@ \***************************************************************************/ #include "jabber.h" +#include "md5.h" +#include "base64.h" static unsigned int next_id = 1; @@ -133,11 +135,21 @@ void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_ca { struct jabber_data *jd = ic->proto_data; struct jabber_cache_entry *entry = g_new0( struct jabber_cache_entry, 1 ); - char *id; + md5_state_t id_hash; + md5_byte_t id_sum[16]; + char *id, *asc_hash; - id = g_strdup_printf( "%s%05x", jd->cached_id_prefix, ( next_id++ ) & 0xfffff ); + next_id ++; + + id_hash = jd->cached_id_prefix; + md5_append( &id_hash, (md5_byte_t*) &next_id, sizeof( next_id ) ); + md5_finish( &id_hash, id_sum ); + asc_hash = base64_encode( id_sum, 12 ); + + id = g_strdup_printf( "%s%s", JABBER_CACHED_ID, asc_hash ); xt_add_attr( node, "id", id ); g_free( id ); + g_free( asc_hash ); entry->node = node; entry->func = func; @@ -183,7 +195,7 @@ xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node * char *s; if( ( s = xt_find_attr( node, "id" ) ) == NULL || - strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 ) + strncmp( s, JABBER_CACHED_ID, strlen( JABBER_CACHED_ID ) ) != 0 ) { /* Silently ignore it, without an ID (or a non-cache ID) we don't know how to handle the packet and we @@ -195,8 +207,14 @@ xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node * if( entry == NULL ) { + /* + There's no longer an easy way to see if we generated this + one or someone else, and there's a ten-minute timeout anyway, + so meh. + imcb_log( ic, "Warning: Received %s-%s packet with unknown/expired ID %s!", node->name, xt_find_attr( node, "type" ) ? : "(no type)", s ); + */ } else if( entry->func ) { @@ -245,8 +263,10 @@ struct jabber_buddy_ask_data char *realname; }; -static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla ) +static void jabber_buddy_ask_yes( void *data ) { + struct jabber_buddy_ask_data *bla = data; + presence_send_request( bla->ic, bla->handle, "subscribed" ); if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) @@ -256,8 +276,10 @@ static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla g_free( bla ); } -static void jabber_buddy_ask_no( gpointer w, struct jabber_buddy_ask_data *bla ) +static void jabber_buddy_ask_no( void *data ) { + struct jabber_buddy_ask_data *bla = data; + presence_send_request( bla->ic, bla->handle, "subscribed" ); g_free( bla->handle ); @@ -285,8 +307,13 @@ char *jabber_normalize( const char *orig ) len = strlen( orig ); new = g_new( char, len + 1 ); - for( i = 0; i < len; i ++ ) + + /* So it turns out the /resource part is case sensitive. Yeah, and + it's Unicode but feck Unicode. :-P So stop once we see a slash. */ + for( i = 0; i < len && orig[i] != '/' ; i ++ ) new[i] = tolower( orig[i] ); + for( ; orig[i]; i ++ ) + new[i] = orig[i]; new[i] = 0; return new; @@ -329,7 +356,7 @@ struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid_ for( bi = bud; bi; bi = bi->next ) { /* Check for dupes. */ - if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) + if( strcmp( bi->resource, s + 1 ) == 0 ) { *s = '/'; g_free( new ); @@ -382,7 +409,7 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, if( ( s = strchr( jid, '/' ) ) ) { - int none_found = 0; + int bare_exists = 0; *s = 0; if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) ) @@ -405,21 +432,19 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, /* See if there's an exact match. */ for( ; bud; bud = bud->next ) - if( g_strcasecmp( bud->resource, s + 1 ) == 0 ) + if( strcmp( bud->resource, s + 1 ) == 0 ) break; } else { - /* This hack is there to make sure that O_CREAT will - work if there's already another resouce present - for this JID, even if it's an unknown buddy. This - is done to handle conferences properly. */ - none_found = 1; - /* TODO(wilmer): Find out what I was thinking when I - wrote this??? And then fix it. This makes me sad... */ + /* This variable tells the if down here that the bare + JID already exists and we should feel free to add + more resources, if the caller asked for that. */ + bare_exists = 1; } - if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) ) + if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && + ( !bare_exists || imcb_find_buddy( ic, jid ) ) ) { *s = '/'; bud = jabber_buddy_add( ic, jid ); @@ -444,7 +469,7 @@ struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid_, else if( bud->resource && ( flags & GET_BUDDY_EXACT ) ) /* We want an exact match, so in thise case there shouldn't be a /resource. */ return NULL; - else if( ( bud->resource == NULL || bud->next == NULL ) ) + else if( bud->resource == NULL || bud->next == NULL ) /* No need for selection if there's only one option. */ return bud; else if( flags & GET_BUDDY_FIRST ) @@ -520,7 +545,9 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) /* If there's only one item in the list (and if the resource matches), removing it is simple. (And the hash reference should be removed too!) */ - if( bud->next == NULL && ( ( s == NULL || bud->resource == NULL ) || g_strcasecmp( bud->resource, s + 1 ) == 0 ) ) + if( bud->next == NULL && + ( ( s == NULL && bud->resource == NULL ) || + ( bud->resource && s && strcmp( bud->resource, s + 1 ) == 0 ) ) ) { g_hash_table_remove( jd->buddies, bud->bare_jid ); g_free( bud->bare_jid ); @@ -543,7 +570,7 @@ int jabber_buddy_remove( struct im_connection *ic, char *full_jid_ ) else { for( bi = bud, prev = NULL; bi; bi = (prev=bi)->next ) - if( g_strcasecmp( bi->resource, s + 1 ) == 0 ) + if( strcmp( bi->resource, s + 1 ) == 0 ) break; g_free( full_jid ); diff --git a/protocols/jabber/message.c b/protocols/jabber/message.c index fab62a91..6cb67d42 100644 --- a/protocols/jabber/message.c +++ b/protocols/jabber/message.c @@ -48,6 +48,23 @@ xt_status jabber_pkt_message( struct xt_node *node, gpointer data ) else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */ { GString *fullmsg = g_string_new( "" ); + + for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next ) + { + char *ns = xt_find_attr( c, "xmlns" ), *room; + struct xt_node *inv, *reason; + + if( strcmp( ns, XMLNS_MUC_USER ) == 0 && + ( inv = xt_find_node( c->children, "invite" ) ) ) + { + room = from; + from = xt_find_attr( inv, "from" ) ? : from; + + g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Invitation to chatroom %s >>\n", room ); + if( ( reason = xt_find_node( inv->children, "reason" ) ) && reason->text_len > 0 ) + g_string_append( fullmsg, reason->text ); + } + } if( ( s = strchr( from, '/' ) ) ) { diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c deleted file mode 100644 index 62549eb5..00000000 --- a/protocols/jabber/xmltree.c +++ /dev/null @@ -1,589 +0,0 @@ -/***************************************************************************\ -* * -* BitlBee - An IRC to IM gateway * -* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * -* * -* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * -* * -* This library is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public * -* License as published by the Free Software Foundation, version * -* 2.1. * -* * -* This library is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * -* Lesser General Public License for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this library; if not, write to the Free Software Foundation, * -* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * -* * -****************************************************************************/ - -#include <glib.h> -#include <string.h> -#include <unistd.h> -#include <ctype.h> -#include <stdio.h> - -#include "xmltree.h" - -static void xt_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - struct xt_node *node = g_new0( struct xt_node, 1 ), *nt; - int i; - - node->parent = xt->cur; - node->name = g_strdup( element_name ); - - /* First count the number of attributes */ - for( i = 0; attr_names[i]; i ++ ); - - /* Then allocate a NULL-terminated array. */ - node->attr = g_new0( struct xt_attr, i + 1 ); - - /* And fill it, saving one variable by starting at the end. */ - for( i --; i >= 0; i -- ) - { - node->attr[i].key = g_strdup( attr_names[i] ); - node->attr[i].value = g_strdup( attr_values[i] ); - } - - /* Add it to the linked list of children nodes, if we have a current - node yet. */ - if( xt->cur ) - { - if( xt->cur->children ) - { - for( nt = xt->cur->children; nt->next; nt = nt->next ); - nt->next = node; - } - else - { - xt->cur->children = node; - } - } - else if( xt->root ) - { - /* ERROR situation: A second root-element??? */ - } - - /* Now this node will be the new current node. */ - xt->cur = node; - /* And maybe this is the root? */ - if( xt->root == NULL ) - xt->root = node; -} - -static void xt_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - struct xt_node *node = xt->cur; - - if( node == NULL ) - return; - - /* FIXME: Does g_renew also OFFICIALLY accept NULL arguments? */ - node->text = g_renew( char, node->text, node->text_len + text_len + 1 ); - memcpy( node->text + node->text_len, text, text_len ); - node->text_len += text_len; - /* Zero termination is always nice to have. */ - node->text[node->text_len] = 0; -} - -static void xt_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - - xt->cur->flags |= XT_COMPLETE; - xt->cur = xt->cur->parent; -} - -GMarkupParser xt_parser_funcs = -{ - xt_start_element, - xt_end_element, - xt_text, - NULL, - NULL -}; - -struct xt_parser *xt_new( gpointer data ) -{ - struct xt_parser *xt = g_new0( struct xt_parser, 1 ); - - xt->data = data; - xt_reset( xt ); - - return xt; -} - -/* Reset the parser, flush everything we have so far. For example, we need - this for XMPP when doing TLS/SASL to restart the stream. */ -void xt_reset( struct xt_parser *xt ) -{ - if( xt->parser ) - g_markup_parse_context_free( xt->parser ); - - xt->parser = g_markup_parse_context_new( &xt_parser_funcs, 0, xt, NULL ); - - if( xt->root ) - { - xt_free_node( xt->root ); - xt->root = NULL; - xt->cur = NULL; - } -} - -/* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on - end-of-stream and 1 otherwise. */ -int xt_feed( struct xt_parser *xt, char *text, int text_len ) -{ - if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) ) - { - return -1; - } - - return !( xt->root && xt->root->flags & XT_COMPLETE ); -} - -/* Find completed nodes and see if a handler has to be called. Passing - a node isn't necessary if you want to start at the root, just pass - NULL. This second argument is needed for recursive calls. */ -int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) -{ - struct xt_node *c; - xt_status st; - int i; - - /* Just in case someone likes infinite loops... */ - if( xt->root == NULL ) - return 0; - - if( node == NULL ) - return xt_handle( xt, xt->root, depth ); - - if( depth != 0 ) - for( c = node->children; c; c = c->next ) - if( !xt_handle( xt, c, depth > 0 ? depth - 1 : depth ) ) - return 0; - - if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) ) - { - for( i = 0; xt->handlers[i].func; i ++ ) - { - /* This one is fun! \o/ */ - - /* If handler.name == NULL it means it should always match. */ - if( ( xt->handlers[i].name == NULL || - /* If it's not, compare. There should always be a name. */ - g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) && - /* If handler.parent == NULL, it's a match. */ - ( xt->handlers[i].parent == NULL || - /* If there's a parent node, see if the name matches. */ - ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 : - /* If there's no parent, the handler should mention <root> as a parent. */ - g_strcasecmp( xt->handlers[i].parent, "<root>" ) == 0 ) ) ) - { - st = xt->handlers[i].func( node, xt->data ); - - if( st == XT_ABORT ) - return 0; - else if( st != XT_NEXT ) - break; - } - } - - node->flags |= XT_SEEN; - } - - return 1; -} - -/* Garbage collection: Cleans up all nodes that are handled. Useful for - streams because there's no reason to keep a complete packet history - in memory. */ -void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ) -{ - struct xt_node *c, *prev; - - if( !xt || !xt->root ) - return; - - if( node == NULL ) - return xt_cleanup( xt, xt->root, depth ); - - if( node->flags & XT_SEEN && node == xt->root ) - { - xt_free_node( xt->root ); - xt->root = xt->cur = NULL; - /* xt->cur should be NULL already, BTW... */ - - return; - } - - /* c contains the current node, prev the previous node (or NULL). - I admit, this one's pretty horrible. */ - for( c = node->children, prev = NULL; c; prev = c, c = c ? c->next : node->children ) - { - if( c->flags & XT_SEEN ) - { - /* Remove the node from the linked list. */ - if( prev ) - prev->next = c->next; - else - node->children = c->next; - - xt_free_node( c ); - - /* Since the for loop wants to get c->next, make sure - c points at something that exists (and that c->next - will actually be the next item we should check). c - can be NULL now, if we just removed the first item. - That explains the ? thing in for(). */ - c = prev; - } - else - { - /* This node can't be cleaned up yet, but maybe a - subnode can. */ - if( depth != 0 ) - xt_cleanup( xt, c, depth > 0 ? depth - 1 : depth ); - } - } -} - -static void xt_to_string_real( struct xt_node *node, GString *str ) -{ - char *buf; - struct xt_node *c; - int i; - - g_string_append_printf( str, "<%s", node->name ); - - for( i = 0; node->attr[i].key; i ++ ) - { - buf = g_markup_printf_escaped( " %s=\"%s\"", node->attr[i].key, node->attr[i].value ); - g_string_append( str, buf ); - g_free( buf ); - } - - if( node->text == NULL && node->children == NULL ) - { - g_string_append( str, "/>" ); - return; - } - - g_string_append( str, ">" ); - if( node->text_len > 0 ) - { - buf = g_markup_escape_text( node->text, node->text_len ); - g_string_append( str, buf ); - g_free( buf ); - } - - for( c = node->children; c; c = c->next ) - xt_to_string_real( c, str ); - - g_string_append_printf( str, "</%s>", node->name ); -} - -char *xt_to_string( struct xt_node *node ) -{ - GString *ret; - char *real; - - ret = g_string_new( "" ); - xt_to_string_real( node, ret ); - - real = ret->str; - g_string_free( ret, FALSE ); - - return real; -} - -#ifdef DEBUG -void xt_print( struct xt_node *node ) -{ - int i; - struct xt_node *c; - - /* Indentation */ - for( c = node; c->parent; c = c->parent ) - printf( "\t" ); - - /* Start the tag */ - printf( "<%s", node->name ); - - /* Print the attributes */ - for( i = 0; node->attr[i].key; i ++ ) - printf( " %s=\"%s\"", node->attr[i].key, g_markup_escape_text( node->attr[i].value, -1 ) ); - - /* /> in case there's really *nothing* inside this tag, otherwise - just >. */ - /* If this tag doesn't have any content at all... */ - if( node->text == NULL && node->children == NULL ) - { - printf( "/>\n" ); - return; - /* Then we're finished! */ - } - - /* Otherwise... */ - printf( ">" ); - - /* Only print the text if it contains more than whitespace (TEST). */ - if( node->text_len > 0 ) - { - for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ ); - if( node->text[i] ) - printf( "%s", g_markup_escape_text( node->text, -1 ) ); - } - - if( node->children ) - printf( "\n" ); - - for( c = node->children; c; c = c->next ) - xt_print( c ); - - if( node->children ) - for( c = node; c->parent; c = c->parent ) - printf( "\t" ); - - /* Non-empty tag is now finished. */ - printf( "</%s>\n", node->name ); -} -#endif - -struct xt_node *xt_dup( struct xt_node *node ) -{ - struct xt_node *dup = g_new0( struct xt_node, 1 ); - struct xt_node *c, *dc = NULL; - int i; - - /* Let's NOT copy the parent element here BTW! Only do it for children. */ - - dup->name = g_strdup( node->name ); - dup->flags = node->flags; - if( node->text ) - { - dup->text = g_memdup( node->text, node->text_len + 1 ); - dup->text_len = node->text_len; - } - - /* Count the number of attributes and allocate the new array. */ - for( i = 0; node->attr[i].key; i ++ ); - dup->attr = g_new0( struct xt_attr, i + 1 ); - - /* Copy them all! */ - for( i --; i >= 0; i -- ) - { - dup->attr[i].key = g_strdup( node->attr[i].key ); - dup->attr[i].value = g_strdup( node->attr[i].value ); - } - - /* This nice mysterious loop takes care of the children. */ - for( c = node->children; c; c = c->next ) - { - if( dc == NULL ) - dc = dup->children = xt_dup( c ); - else - dc = ( dc->next = xt_dup( c ) ); - - dc->parent = dup; - } - - return dup; -} - -/* Frees a node. This doesn't clean up references to itself from parents! */ -void xt_free_node( struct xt_node *node ) -{ - int i; - - if( !node ) - return; - - g_free( node->name ); - g_free( node->text ); - - for( i = 0; node->attr[i].key; i ++ ) - { - g_free( node->attr[i].key ); - g_free( node->attr[i].value ); - } - g_free( node->attr ); - - while( node->children ) - { - struct xt_node *next = node->children->next; - - xt_free_node( node->children ); - node->children = next; - } - - g_free( node ); -} - -void xt_free( struct xt_parser *xt ) -{ - if( !xt ) - return; - - if( xt->root ) - xt_free_node( xt->root ); - - g_markup_parse_context_free( xt->parser ); - - g_free( xt ); -} - -/* To find a node's child with a specific name, pass the node's children - list, not the node itself! The reason you have to do this by hand: So - that you can also use this function as a find-next. */ -struct xt_node *xt_find_node( struct xt_node *node, const char *name ) -{ - while( node ) - { - if( g_strcasecmp( node->name, name ) == 0 ) - break; - - node = node->next; - } - - return node; -} - -char *xt_find_attr( struct xt_node *node, const char *key ) -{ - int i; - - if( !node ) - return NULL; - - for( i = 0; node->attr[i].key; i ++ ) - if( g_strcasecmp( node->attr[i].key, key ) == 0 ) - break; - - return node->attr[i].value; -} - -struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ) -{ - struct xt_node *node, *c; - - node = g_new0( struct xt_node, 1 ); - node->name = g_strdup( name ); - node->children = children; - node->attr = g_new0( struct xt_attr, 1 ); - - if( text ) - { - node->text_len = strlen( text ); - node->text = g_memdup( text, node->text_len + 1 ); - } - - for( c = children; c; c = c->next ) - { - if( c->parent != NULL ) - { - /* ERROR CONDITION: They seem to have a parent already??? */ - } - - c->parent = node; - } - - return node; -} - -void xt_add_child( struct xt_node *parent, struct xt_node *child ) -{ - struct xt_node *node; - - /* This function can actually be used to add more than one child, so - do handle this properly. */ - for( node = child; node; node = node->next ) - { - if( node->parent != NULL ) - { - /* ERROR CONDITION: They seem to have a parent already??? */ - } - - node->parent = parent; - } - - if( parent->children == NULL ) - { - parent->children = child; - } - else - { - for( node = parent->children; node->next; node = node->next ); - node->next = child; - } -} - -void xt_add_attr( struct xt_node *node, const char *key, const char *value ) -{ - int i; - - /* Now actually it'd be nice if we can also change existing attributes - (which actually means this function doesn't have the right name). - So let's find out if we have this attribute already... */ - for( i = 0; node->attr[i].key; i ++ ) - if( strcmp( node->attr[i].key, key ) == 0 ) - break; - - if( node->attr[i].key == NULL ) - { - /* If not, allocate space for a new attribute. */ - node->attr = g_renew( struct xt_attr, node->attr, i + 2 ); - node->attr[i].key = g_strdup( key ); - node->attr[i+1].key = NULL; - } - else - { - /* Otherwise, free the old value before setting the new one. */ - g_free( node->attr[i].value ); - } - - node->attr[i].value = g_strdup( value ); -} - -int xt_remove_attr( struct xt_node *node, const char *key ) -{ - int i, last; - - for( i = 0; node->attr[i].key; i ++ ) - if( strcmp( node->attr[i].key, key ) == 0 ) - break; - - /* If we didn't find the attribute... */ - if( node->attr[i].key == NULL ) - return 0; - - g_free( node->attr[i].key ); - g_free( node->attr[i].value ); - - /* If it's the last, this is easy: */ - if( node->attr[i+1].key == NULL ) - { - node->attr[i].key = node->attr[i].value = NULL; - } - else /* It's also pretty easy, actually. */ - { - /* Find the last item. */ - for( last = i + 1; node->attr[last+1].key; last ++ ); - - node->attr[i] = node->attr[last]; - node->attr[last].key = NULL; - node->attr[last].value = NULL; - } - - /* Let's not bother with reallocating memory here. It takes time and - most packets don't stay in memory for long anyway. */ - - return 1; -} diff --git a/protocols/jabber/xmltree.h b/protocols/jabber/xmltree.h deleted file mode 100644 index b8b61641..00000000 --- a/protocols/jabber/xmltree.h +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************\ -* * -* BitlBee - An IRC to IM gateway * -* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * -* * -* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * -* * -* This library is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public * -* License as published by the Free Software Foundation, version * -* 2.1. * -* * -* This library is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * -* Lesser General Public License for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this library; if not, write to the Free Software Foundation, * -* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * -* * -****************************************************************************/ - -#ifndef _XMLTREE_H -#define _XMLTREE_H - -typedef enum -{ - XT_COMPLETE = 1, /* </tag> reached */ - XT_SEEN = 2, /* Handler called (or not defined) */ -} xt_flags; - -typedef enum -{ - XT_ABORT, /* Abort, don't handle the rest anymore */ - XT_HANDLED, /* Handled this tag properly, go to the next one */ - XT_NEXT /* Try if there's another matching handler */ -} xt_status; - -struct xt_attr -{ - char *key, *value; -}; - -struct xt_node -{ - struct xt_node *parent; - struct xt_node *children; - - char *name; - struct xt_attr *attr; - char *text; - int text_len; - - struct xt_node *next; - xt_flags flags; -}; - -typedef xt_status (*xt_handler_func) ( struct xt_node *node, gpointer data ); - -struct xt_handler_entry -{ - char *name, *parent; - xt_handler_func func; -}; - -struct xt_parser -{ - GMarkupParseContext *parser; - struct xt_node *root; - struct xt_node *cur; - - struct xt_handler_entry *handlers; - gpointer data; - - GError *gerr; -}; - -struct xt_parser *xt_new( gpointer data ); -void xt_reset( struct xt_parser *xt ); -int xt_feed( struct xt_parser *xt, char *text, int text_len ); -int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); -void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ); -char *xt_to_string( struct xt_node *node ); -void xt_print( struct xt_node *node ); -struct xt_node *xt_dup( struct xt_node *node ); -void xt_free_node( struct xt_node *node ); -void xt_free( struct xt_parser *xt ); -struct xt_node *xt_find_node( struct xt_node *node, const char *name ); -char *xt_find_attr( struct xt_node *node, const char *key ); - -struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ); -void xt_add_child( struct xt_node *parent, struct xt_node *child ); -void xt_add_attr( struct xt_node *node, const char *key, const char *value ); -int xt_remove_attr( struct xt_node *node, const char *key ); - -#endif |