Index: protocols/jabber/io.c
===================================================================
--- protocols/jabber/io.c	(revision 038d17f834219505cbbdae469b2b150117467dd0)
+++ protocols/jabber/io.c	(revision 861c199fb60fecf5dab96e0ed9d4b0cf0c57822f)
@@ -214,5 +214,5 @@
 					else
 					{
-						return jabber_start_iq_auth( gc );
+						return jabber_init_iq_auth( gc );
 					}
 				}
@@ -351,5 +351,5 @@
 	else if( !( jd->flags & JFLAG_AUTHENTICATED ) && sasl_supported( gc ) )
 	{
-		if( !jabber_start_iq_auth( gc ) )
+		if( !jabber_init_iq_auth( gc ) )
 			return XT_ABORT;
 	}
@@ -360,5 +360,5 @@
 		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 ) )
@@ -373,5 +373,5 @@
 		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 ) )
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision 038d17f834219505cbbdae469b2b150117467dd0)
+++ protocols/jabber/iq.c	(revision 861c199fb60fecf5dab96e0ed9d4b0cf0c57822f)
@@ -28,144 +28,35 @@
 	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;
-	
-	query = xt_find_node( node->children, "query" );
+	char *type, *s;
+	
 	type = xt_find_attr( node, "type" );
 	
 	if( !type )
-		return XT_HANDLED;	/* Ignore it for now, don't know what's best... */
-	
-	xmlns = xt_find_attr( query, "xmlns" );
-	
-	if( ( s = xt_find_attr( node, "id" ) ) )
-		orig = jabber_cache_get( gc, s );
-	
-	if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:auth" ) == 0 )
-	{
-		/* 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" ) ) )
-		{
-			/* 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;
-		}
-		
-		reply = jabber_make_packet( "iq", "set", NULL, reply );
-		jabber_cache_add( gc, reply );
-		st = jabber_write_packet( gc, reply );
-		
-		return st ? XT_HANDLED : XT_ABORT;
-	}
-	if( strcmp( type, "result" ) == 0 && xmlns && strcmp( xmlns, "jabber:iq:roster" ) == 0 )
-	{
-		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 );
-	}
-	else if( strcmp( type, "result" ) == 0 && orig )
-	{
-		struct xt_node *c;
-		
-		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;
-			}
-		}
-	}
-	else if( strcmp( type, "error" ) == 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 );
-			return XT_ABORT;
-		}
-	}
-	
-	return XT_HANDLED;
-}
-
-int jabber_start_iq_auth( struct gaim_connection *gc )
+	{
+		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;
@@ -177,9 +68,118 @@
 	node = jabber_make_packet( "iq", "get", NULL, node );
 	
-	st = jabber_write_packet( gc, node );
-	
-	xt_free_node( node );
-	return st;
-}
+	jabber_cache_add( gc, node, jabber_do_iq_auth );
+	st = jabber_write_packet( gc, node );
+	
+	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;
+	
+	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" ) ) )
+	{
+		/* 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;
+	}
+	
+	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 )
+	{
+		/* 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;
+}
+
+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 *c;
+	char *s;
+	
+	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;
+	}
+	
+	if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 )
+	{
+		if( !jabber_get_roster( gc ) )
+			return XT_ABORT;
+	}
+	
+	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 )
@@ -194,8 +194,32 @@
 	node = jabber_make_packet( "iq", "get", NULL, node );
 	
-	st = jabber_write_packet( gc, node );
-	
-	xt_free_node( node );
-	return st;
+	jabber_cache_add( gc, node, jabber_parse_roster );
+	st = jabber_write_packet( gc, 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;
 }
 
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision 038d17f834219505cbbdae469b2b150117467dd0)
+++ protocols/jabber/jabber.c	(revision 861c199fb60fecf5dab96e0ed9d4b0cf0c57822f)
@@ -174,5 +174,5 @@
 	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 );
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 038d17f834219505cbbdae469b2b150117467dd0)
+++ protocols/jabber/jabber.h	(revision 861c199fb60fecf5dab96e0ed9d4b0cf0c57822f)
@@ -69,5 +69,5 @@
 };
 
-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
@@ -79,5 +79,6 @@
 /* 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 );
@@ -96,5 +97,5 @@
 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 );
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision 038d17f834219505cbbdae469b2b150117467dd0)
+++ protocols/jabber/jabber_util.c	(revision 861c199fb60fecf5dab96e0ed9d4b0cf0c57822f)
@@ -82,5 +82,5 @@
    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;
@@ -92,13 +92,6 @@
 	
 	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;
 }
 
@@ -113,4 +106,9 @@
 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 )
 {
