aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2006-10-08 20:41:11 +0200
committerWilmer van der Gaast <wilmer@gaast.net>2006-10-08 20:41:11 +0200
commit861c199fb60fecf5dab96e0ed9d4b0cf0c57822f (patch)
tree45a66a0ebd0f1d1d25016490f00471c7a3456927
parent038d17f834219505cbbdae469b2b150117467dd0 (diff)
Moved handling of all IQ packets to event handlers. Cleaned up a LOT of
mess in iq.c!
-rw-r--r--protocols/jabber/io.c8
-rw-r--r--protocols/jabber/iq.c274
-rw-r--r--protocols/jabber/jabber.c2
-rw-r--r--protocols/jabber/jabber.h7
-rw-r--r--protocols/jabber/jabber_util.c16
5 files changed, 165 insertions, 142 deletions
diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c
index c6ad68e0..783d6d2c 100644
--- a/protocols/jabber/io.c
+++ b/protocols/jabber/io.c
@@ -213,7 +213,7 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition
}
else
{
- return jabber_start_iq_auth( gc );
+ return jabber_init_iq_auth( gc );
}
}
}
@@ -350,7 +350,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )
to be XMPP 1.0 compliant! */
else if( !( jd->flags & JFLAG_AUTHENTICATED ) && sasl_supported( gc ) )
{
- if( !jabber_start_iq_auth( gc ) )
+ if( !jabber_init_iq_auth( gc ) )
return XT_ABORT;
}
@@ -359,7 +359,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )
reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) );
xt_add_attr( reply, "xmlns", "urn:ietf:params:xml:ns:xmpp-bind" );
reply = jabber_make_packet( "iq", "set", NULL, reply );
- jabber_cache_add( gc, reply );
+ jabber_cache_add( gc, reply, jabber_pkt_bind_sess );
if( !jabber_write_packet( gc, reply ) )
return XT_ABORT;
@@ -372,7 +372,7 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data )
reply = xt_new_node( "session", NULL, NULL );
xt_add_attr( reply, "xmlns", "urn:ietf:params:xml:ns:xmpp-session" );
reply = jabber_make_packet( "iq", "set", NULL, reply );
- jabber_cache_add( gc, reply );
+ jabber_cache_add( gc, reply, jabber_pkt_bind_sess );
if( !jabber_write_packet( gc, reply ) )
return XT_ABORT;
diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c
index ae4ed099..1b968739 100644
--- a/protocols/jabber/iq.c
+++ b/protocols/jabber/iq.c
@@ -27,161 +27,161 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data )
{
struct gaim_connection *gc = data;
struct jabber_data *jd = gc->proto_data;
- struct xt_node *query, *reply = NULL, *orig = NULL, *c;
- char *s, *type, *xmlns;
- int st;
+ char *type, *s;
- query = xt_find_node( node->children, "query" );
type = xt_find_attr( node, "type" );
if( !type )
- return XT_HANDLED; /* Ignore it for now, don't know what's best... */
+ {
+ hide_login_progress_error( gc, "Received IQ packet without type!" );
+ signoff( gc );
+ return XT_ABORT;
+ }
+
+ if( ( s = xt_find_attr( node, "id" ) ) &&
+ ( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 ) )
+ {
+ struct jabber_cache_entry *entry;
+
+ entry = g_hash_table_lookup( jd->node_cache, s );
+
+ if( entry == NULL )
+ serv_got_crap( gc, "WARNING: Received IQ %s packet with unknown/expired ID %s!", type, s );
+ else if( entry->func )
+ return entry->func( gc, node, entry->node );
+ }
+
+ return XT_HANDLED;
+}
+
+static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig );
+static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig );
+
+int jabber_init_iq_auth( struct gaim_connection *gc )
+{
+ struct jabber_data *jd = gc->proto_data;
+ struct xt_node *node;
+ int st;
+
+ node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) );
+ xt_add_attr( node, "xmlns", "jabber:iq:auth" );
+ node = jabber_make_packet( "iq", "get", NULL, node );
- xmlns = xt_find_attr( query, "xmlns" );
+ jabber_cache_add( gc, node, jabber_do_iq_auth );
+ st = jabber_write_packet( gc, node );
- if( ( s = xt_find_attr( node, "id" ) ) )
- orig = jabber_cache_get( gc, s );
+ return st;
+}
+
+static xt_status jabber_do_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig )
+{
+ struct jabber_data *jd = gc->proto_data;
+ struct xt_node *reply, *query;
+ xt_status st;
+ char *s;
- if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 )
+ query = xt_find_node( node->children, "query" );
+
+ /* Time to authenticate ourselves! */
+ reply = xt_new_node( "query", NULL, NULL );
+ xt_add_attr( reply, "xmlns", "jabber:iq:auth" );
+ xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) );
+ xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) );
+
+ if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) )
{
- /* Time to authenticate ourselves! */
- reply = xt_new_node( "query", NULL, NULL );
- xt_add_attr( reply, "xmlns", "jabber:iq:auth" );
- xt_add_child( reply, xt_new_node( "username", jd->username, NULL ) );
- xt_add_child( reply, xt_new_node( "resource", set_getstr( &gc->acc->set, "resource" ), NULL ) );
+ /* We can do digest authentication, it seems, and of
+ course we prefer that. */
+ SHA_CTX sha;
+ char hash_hex[40];
+ unsigned char hash[20];
+ int i;
- if( xt_find_node( query->children, "digest" ) && ( s = xt_find_attr( jd->xt->root, "id" ) ) )
- {
- /* We can do digest authentication, it seems, and of
- course we prefer that. */
- SHA_CTX sha;
- char hash_hex[40];
- unsigned char hash[20];
- int i;
-
- shaInit( &sha );
- shaUpdate( &sha, (unsigned char*) s, strlen( s ) );
- shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) );
- shaFinal( &sha, hash );
-
- for( i = 0; i < 20; i ++ )
- sprintf( hash_hex + i * 2, "%02x", hash[i] );
-
- xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) );
- }
- else if( xt_find_node( query->children, "password" ) )
- {
- /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */
- xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) );
- }
- else
- {
- xt_free_node( reply );
-
- hide_login_progress( gc, "Can't find suitable authentication method" );
- signoff( gc );
- return XT_ABORT;
- }
+ shaInit( &sha );
+ shaUpdate( &sha, (unsigned char*) s, strlen( s ) );
+ shaUpdate( &sha, (unsigned char*) gc->acc->pass, strlen( gc->acc->pass ) );
+ shaFinal( &sha, hash );
- reply = jabber_make_packet( "iq", "set", NULL, reply );
- jabber_cache_add( gc, reply );
- st = jabber_write_packet( gc, reply );
+ for( i = 0; i < 20; i ++ )
+ sprintf( hash_hex + i * 2, "%02x", hash[i] );
- return st ? XT_HANDLED : XT_ABORT;
+ xt_add_child( reply, xt_new_node( "digest", hash_hex, NULL ) );
}
- if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:roster" ) == 0 )
+ else if( xt_find_node( query->children, "password" ) )
{
- struct xt_node *node;
-
- node = query->children;
- while( ( node = xt_find_node( node, "item" ) ) )
- {
- char *jid = xt_find_attr( node, "jid" );
- char *name = xt_find_attr( node, "name" );
- char *sub = xt_find_attr( node, "subscription" );
-
- if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
- add_buddy( gc, NULL, jid, name );
-
- node = node->next;
- }
-
- account_online( gc );
+ /* We'll have to stick with plaintext. Let's hope we're using SSL/TLS... */
+ xt_add_child( reply, xt_new_node( "password", gc->acc->pass, NULL ) );
}
- else if( strcmp( type, "result" ) == 0 && orig )
+ else
{
- struct xt_node *c;
+ xt_free_node( reply );
- if( !( jd->flags & JFLAG_AUTHENTICATED ) &&
- ( c = xt_find_node( orig->children, "query" ) ) &&
- ( c = xt_find_node( c->children, "username" ) ) &&
- c->text_len )
- {
- /* This happens when we just successfully authenticated
- the old (non-SASL) way. */
- jd->flags |= JFLAG_AUTHENTICATED;
- if( !jabber_get_roster( gc ) )
- return XT_ABORT;
- }
- /* Tricky: Look for <bind> in the reply, because the server
- should confirm the chosen resource string there. For
- <session>, however, look in the cache, because the server
- will probably not include it in its reply. */
- else if( ( c = xt_find_node( node->children, "bind" ) ) ||
- ( c = xt_find_node( orig->children, "session" ) ) )
- {
- if( strcmp( c->name, "bind" ) == 0 )
- {
- c = xt_find_node( c->children, "jid" );
- if( c && c->text_len && ( s = strchr( c->text, '/' ) ) &&
- strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 )
- serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 );
-
- jd->flags &= ~JFLAG_WAIT_BIND;
- }
- else if( strcmp( c->name, "session" ) == 0 )
- jd->flags &= ~JFLAG_WAIT_SESSION;
-
- if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
- {
- if( !jabber_get_roster( gc ) )
- return XT_ABORT;
- }
- }
+ hide_login_progress( gc, "Can't find suitable authentication method" );
+ signoff( gc );
+ return XT_ABORT;
}
- else if( strcmp( type, "error" ) == 0 )
+
+ reply = jabber_make_packet( "iq", "set", NULL, reply );
+ jabber_cache_add( gc, reply, jabber_finish_iq_auth );
+ st = jabber_write_packet( gc, reply );
+
+ return st ? XT_HANDLED : XT_ABORT;
+}
+
+static xt_status jabber_finish_iq_auth( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig )
+{
+ char *type = xt_find_attr( node, "type" );
+ struct jabber_data *jd = gc->proto_data;
+
+ if( strcmp( type, "error" ) == 0 )
+ {
+ hide_login_progress( gc, "Authentication failure" );
+ signoff( gc );
+ return XT_ABORT;
+ }
+ else if( strcmp( type, "result" ) == 0 )
{
- if( !( jd->flags & JFLAG_AUTHENTICATED ) &&
- orig &&
- ( c = xt_find_node( orig->children, "query" ) ) &&
- ( c = xt_find_node( c->children, "username" ) ) &&
- c->text_len )
- {
- hide_login_progress( gc, "Authentication failure" );
- signoff( gc );
+ /* This happens when we just successfully authenticated the
+ old (non-SASL) way. */
+ jd->flags |= JFLAG_AUTHENTICATED;
+ if( !jabber_get_roster( gc ) )
return XT_ABORT;
- }
}
return XT_HANDLED;
}
-int jabber_start_iq_auth( struct gaim_connection *gc )
+xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig )
{
struct jabber_data *jd = gc->proto_data;
- struct xt_node *node;
- int st;
+ struct xt_node *c;
+ char *s;
- node = xt_new_node( "query", NULL, xt_new_node( "username", jd->username, NULL ) );
- xt_add_attr( node, "xmlns", "jabber:iq:auth" );
- node = jabber_make_packet( "iq", "get", NULL, node );
+ if( ( c = xt_find_node( node->children, "bind" ) ) )
+ {
+ c = xt_find_node( c->children, "jid" );
+ if( c && c->text_len && ( s = strchr( c->text, '/' ) ) &&
+ strcmp( s + 1, set_getstr( &gc->acc->set, "resource" ) ) != 0 )
+ serv_got_crap( gc, "Server changed session resource string to `%s'", s + 1 );
+
+ jd->flags &= ~JFLAG_WAIT_BIND;
+ }
+ else
+ {
+ jd->flags &= ~JFLAG_WAIT_SESSION;
+ }
- st = jabber_write_packet( gc, node );
+ if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
+ {
+ if( !jabber_get_roster( gc ) )
+ return XT_ABORT;
+ }
- xt_free_node( node );
- return st;
+ return XT_HANDLED;
}
+static xt_status jabber_parse_roster( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig );
+
int jabber_get_roster( struct gaim_connection *gc )
{
struct xt_node *node;
@@ -193,12 +193,36 @@ int jabber_get_roster( struct gaim_connection *gc )
xt_add_attr( node, "xmlns", "jabber:iq:roster" );
node = jabber_make_packet( "iq", "get", NULL, node );
+ jabber_cache_add( gc, node, jabber_parse_roster );
st = jabber_write_packet( gc, node );
- xt_free_node( node );
return st;
}
+static xt_status jabber_parse_roster( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig )
+{
+ struct xt_node *query, *c;
+
+ query = xt_find_node( node->children, "query" );
+
+ c = query->children;
+ while( ( c = xt_find_node( c, "item" ) ) )
+ {
+ char *jid = xt_find_attr( c, "jid" );
+ char *name = xt_find_attr( c, "name" );
+ char *sub = xt_find_attr( c, "subscription" );
+
+ if( jid && sub && ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
+ add_buddy( gc, NULL, jid, name );
+
+ c = c->next;
+ }
+
+ account_online( gc );
+
+ return XT_HANDLED;
+}
+
int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name )
{
struct xt_node *node;
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 32d1d99d..b508cb45 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -173,7 +173,7 @@ static void jabber_get_info( struct gaim_connection *gc, char *who )
node = xt_new_node( "query", NULL, NULL );
xt_add_attr( node, "xmlns", "http://jabber.org/protocol/disco#info" );
node = jabber_make_packet( "iq", "get", who, node );
- jabber_cache_add( gc, node );
+ // jabber_cache_add( gc, node, );
jabber_write_packet( gc, node );
}
diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h
index 58a81810..6791a0f5 100644
--- a/protocols/jabber/jabber.h
+++ b/protocols/jabber/jabber.h
@@ -68,7 +68,7 @@ struct jabber_away_state
char *full_name;
};
-typedef xt_status (*jabber_cache_event) ( struct gaim_connection *gc, struct xt_node *packet );
+typedef xt_status (*jabber_cache_event) ( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig );
struct jabber_cache_entry
{
@@ -78,7 +78,8 @@ struct jabber_cache_entry
/* iq.c */
xt_status jabber_pkt_iq( struct xt_node *node, gpointer data );
-int jabber_start_iq_auth( struct gaim_connection *gc );
+int jabber_init_iq_auth( struct gaim_connection *gc );
+xt_status jabber_pkt_bind_sess( struct gaim_connection *gc, struct xt_node *node, struct xt_node *orig );
int jabber_get_roster( struct gaim_connection *gc );
int jabber_add_to_roster( struct gaim_connection *gc, char *handle, char *name );
int jabber_remove_from_roster( struct gaim_connection *gc, char *handle );
@@ -95,7 +96,7 @@ int presence_send_request( struct gaim_connection *gc, char *handle, char *reque
char *set_eval_priority( set_t *set, char *value );
char *set_eval_tls( set_t *set, char *value );
struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children );
-void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node );
+void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node, jabber_cache_event func );
struct xt_node *jabber_cache_get( struct gaim_connection *gc, char *id );
void jabber_cache_entry_free( gpointer entry );
void jabber_cache_clean( struct gaim_connection *gc );
diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c
index 11156258..f26b9617 100644
--- a/protocols/jabber/jabber_util.c
+++ b/protocols/jabber/jabber_util.c
@@ -81,7 +81,7 @@ struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_
/* Cache a node/packet for later use. Mainly useful for IQ packets if you need
them when you receive the response. Use this BEFORE sending the packet so
it'll get an id= tag, and do NOT free() the packet after writing it! */
-void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node )
+void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node, jabber_cache_event func )
{
struct jabber_data *jd = gc->proto_data;
char *id = g_strdup_printf( "BeeX%04x", next_id++ );
@@ -91,17 +91,10 @@ void jabber_cache_add( struct gaim_connection *gc, struct xt_node *node )
g_free( id );
entry->node = node;
+ entry->func = func;
g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry );
}
-struct xt_node *jabber_cache_get( struct gaim_connection *gc, char *id )
-{
- struct jabber_data *jd = gc->proto_data;
- struct jabber_cache_entry *entry = g_hash_table_lookup( jd->node_cache, id );
-
- return entry ? entry->node : NULL;
-}
-
void jabber_cache_entry_free( gpointer data )
{
struct jabber_cache_entry *entry = data;
@@ -112,6 +105,11 @@ void jabber_cache_entry_free( gpointer data )
gboolean jabber_cache_clean_entry( gpointer key, gpointer entry, gpointer nullpointer );
+/* This one should be called from time to time (from keepalive, in this case)
+ to make sure things don't stay in the node cache forever. By marking nodes
+ during the first run and deleting marked nodes during a next run, every
+ node should be available in the cache for at least a minute (assuming the
+ function is indeed called every minute). */
void jabber_cache_clean( struct gaim_connection *gc )
{
struct jabber_data *jd = gc->proto_data;