Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision 2ff20765990c756533957e8da9c7c29dd3102e79)
+++ protocols/jabber/jabber_util.c	(revision 979cfb448cc233e29ceb6cd43f99fb4104728be6)
@@ -97,5 +97,5 @@
 }
 
-struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code )
+struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type )
 {
 	struct xt_node *node, *c;
@@ -109,8 +109,4 @@
 	c = xt_new_node( "error", NULL, c );
 	xt_add_attr( c, "type", err_type );
-	
-	/* Add the error code, if present */
-	if (err_code)
-		xt_add_attr( c, "code", err_code );
 	
 	/* To make the actual error packet, we copy the original packet and
@@ -146,4 +142,5 @@
 	entry->node = node;
 	entry->func = func;
+	entry->saved_at = time( NULL );
 	g_hash_table_insert( jd->node_cache, xt_find_attr( node, "id" ), entry );
 }
@@ -167,20 +164,45 @@
 {
 	struct jabber_data *jd = ic->proto_data;
-	
-	g_hash_table_foreach_remove( jd->node_cache, jabber_cache_clean_entry, NULL );
-}
-
-gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer nullpointer )
+	time_t threshold = time( NULL ) - JABBER_CACHE_MAX_AGE;
+	
+	g_hash_table_foreach_remove( jd->node_cache, jabber_cache_clean_entry, &threshold );
+}
+
+gboolean jabber_cache_clean_entry( gpointer key, gpointer entry_, gpointer threshold_ )
 {
 	struct jabber_cache_entry *entry = entry_;
-	struct xt_node *node = entry->node;
-	
-	if( node->flags & XT_SEEN )
-		return TRUE;
-	else
-	{
-		node->flags |= XT_SEEN;
-		return FALSE;
-	}
+	time_t *threshold = threshold_;
+	
+	return entry->saved_at < *threshold;
+}
+
+xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node )
+{
+	struct jabber_data *jd = ic->proto_data;
+	struct jabber_cache_entry *entry;
+	char *s;
+	
+	if( ( s = xt_find_attr( node, "id" ) ) == NULL ||
+	    strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 )
+	{
+		/* Silently ignore it, without an ID (or a non-cache
+		   ID) we don't know how to handle the packet and we
+		   probably don't have to. */
+		return XT_HANDLED;
+	}
+	
+	entry = g_hash_table_lookup( jd->node_cache, s );
+	
+	if( entry == NULL )
+	{
+		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 )
+	{
+		return entry->func( ic, node, entry->node );
+	}
+	
+	return XT_HANDLED;
 }
 
@@ -265,12 +287,5 @@
 	new = g_new( char, len + 1 );
 	for( i = 0; i < len; i ++ )
-	{
-		/* don't normalize the resource */
-		if( orig[i] == '/' )
-			break;
 		new[i] = tolower( orig[i] );
-	}
-	for( ; i < len; i ++ )
-		new[i] = orig[i];
 	
 	new[i] = 0;
@@ -373,17 +388,24 @@
 		if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) )
 		{
+			/* Just return the first one for this bare JID. */
+			if( flags & GET_BUDDY_FIRST )
+			{
+				*s = '/';
+				g_free( jid );
+				return bud;
+			}
+			
 			/* Is this one of those no-resource buddies? */
 			if( bud->resource == NULL )
 			{
+				*s = '/';
 				g_free( jid );
 				return NULL;
 			}
-			else
-			{
-				/* See if there's an exact match. */
-				for( ; bud; bud = bud->next )
-					if( g_strcasecmp( bud->resource, s + 1 ) == 0 )
-						break;
-			}
+			
+			/* See if there's an exact match. */
+			for( ; bud; bud = bud->next )
+				if( g_strcasecmp( bud->resource, s + 1 ) == 0 )
+					break;
 		}
 		else
@@ -394,4 +416,6 @@
 			   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... */
 		}
 		
@@ -423,4 +447,7 @@
 		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 )
+			/* Looks like the caller doesn't care about details. */
 			return bud;
 		
@@ -595,21 +622,4 @@
 }
 
-struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name )
-{
-	char *normalized = jabber_normalize( name );
-	struct groupchat *ret;
-	struct jabber_chat *jc;
-	
-	for( ret = ic->groupchats; ret; ret = ret->next )
-	{
-		jc = ret->data;
-		if( strcmp( normalized, jc->name ) == 0 )
-			break;
-	}
-	g_free( normalized );
-	
-	return ret;
-}
-
 time_t jabber_get_timestamp( struct xt_node *xt )
 {
@@ -663,8 +673,12 @@
 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns )
 {
-	struct jabber_error *err = g_new0( struct jabber_error, 1 );
+	struct jabber_error *err;
 	struct xt_node *c;
 	char *s;
 	
+	if( node == NULL )
+		return NULL;
+	
+	err = g_new0( struct jabber_error, 1 );
 	err->type = xt_find_attr( node, "type" );
 	
