Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision 47d3ac46306965e9db66096eef8c60c8e7985950)
+++ protocols/jabber/jabber.c	(revision 0d3f30f5449cf1730c006314f3dd60843e911ad1)
@@ -217,10 +217,10 @@
 	int st;
 	
-	bud = jabber_buddy_by_jid( gc, who );
+	bud = jabber_buddy_by_jid( gc, who, 0 );
 	
 	node = xt_new_node( "body", message, NULL );
 	node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node );
 	
-	if( ( jd->flags & JFLAG_WANT_TYPING ) && bud &&
+	if( bud && ( jd->flags & JFLAG_WANT_TYPING ) &&
 	    ( ( bud->flags & JBFLAG_DOES_XEP85 ) ||
 	     !( bud->flags & JBFLAG_PROBED_XEP85 ) ) )
@@ -266,12 +266,16 @@
 	
 	if( strchr( who, '/' ) )
-		bud = jabber_buddy_by_jid( gc, who );
+		bud = jabber_buddy_by_jid( gc, who, 0 );
 	else
-		bud = g_hash_table_lookup( jd->buddies, who );
+	{
+		char *s = jabber_normalize( who );
+		bud = g_hash_table_lookup( jd->buddies, s );
+		g_free( s );
+	}
 	
 	while( bud )
 	{
-		serv_got_crap( gc, "Buddy %s/%s (%d) information:\nAway state: %s\nAway message: %s",
-		                   bud->handle, bud->resource, bud->priority,
+		serv_got_crap( gc, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s",
+		                   bud->full_jid, bud->priority,
 		                   bud->away_state ? bud->away_state->full_name : "(none)",
 		                   bud->away_message ? : "(none)" );
@@ -279,5 +283,5 @@
 	}
 	
-	jabber_get_vcard( gc, bud ? bud->handle : who );
+	jabber_get_vcard( gc, bud ? bud->full_jid : who );
 }
 
@@ -329,5 +333,5 @@
 	jd->flags |= JFLAG_WANT_TYPING;
 	
-	if( ( bud = jabber_buddy_by_jid( gc, who ) ) == NULL )
+	if( ( bud = jabber_buddy_by_jid( gc, who, 0 ) ) == NULL )
 	{
 		/* Sending typing notifications to unknown buddies is
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 47d3ac46306965e9db66096eef8c60c8e7985950)
+++ protocols/jabber/jabber.h	(revision 0d3f30f5449cf1730c006314f3dd60843e911ad1)
@@ -50,5 +50,5 @@
 	JBFLAG_DOES_XEP85 = 2,		/* Set this when the resource seems to support
 	                                   XEP85 (typing notification shite). */
-} jabber_buddy_flag_t;
+} jabber_buddy_flags_t;
 
 struct jabber_data
@@ -93,5 +93,5 @@
 struct jabber_buddy
 {
-	char *handle;
+	char *bare_jid;
 	char *full_jid;
 	char *resource;
@@ -102,5 +102,5 @@
 	
 	time_t last_act;
-	jabber_buddy_flag_t flags;
+	jabber_buddy_flags_t flags;
 	
 	struct jabber_buddy *next;
@@ -160,6 +160,14 @@
 const struct jabber_away_state *jabber_away_state_by_name( char *name );
 void jabber_buddy_ask( struct gaim_connection *gc, char *handle );
+char *jabber_normalize( char *orig );
+
+typedef enum
+{
+	GET_BUDDY_CREAT = 1,	/* Try to create it, if necessary. */
+	GET_BUDDY_EXACT = 2,	/* Get an exact message (only makes sense with bare JIDs). */
+} get_buddy_flags_t;
+
 struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_jid );
-struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid );
+struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid, get_buddy_flags_t flags );
 int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid );
 int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid );
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision 47d3ac46306965e9db66096eef8c60c8e7985950)
+++ protocols/jabber/jabber_util.c	(revision 0d3f30f5449cf1730c006314f3dd60843e911ad1)
@@ -251,21 +251,50 @@
 }
 
+/* Returns a new string. Don't leak it! */
+char *jabber_normalize( char *orig )
+{
+	int len, i;
+	char *new;
+	
+	len = strlen( orig );
+	new = g_new( char, len + 1 );
+	for( i = 0; i < len; i ++ )
+		new[i] = tolower( orig[i] );
+	
+	new[i] = 0;
+	return new;
+}
+
 /* Adds a buddy/resource to our list. Returns NULL if full_jid is not really a
-   FULL jid or if we already have this buddy/resource. */
-struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_jid )
+   FULL jid or if we already have this buddy/resource. XXX: No, great, actually
+   buddies from transports don't (usually) have resources. So we'll really have
+   to deal with that properly. Set their ->resource property to NULL. Do *NOT*
+   allow to mix this stuff, though... */
+struct jabber_buddy *jabber_buddy_add( struct gaim_connection *gc, char *full_jid_ )
 {
 	struct jabber_data *jd = gc->proto_data;
 	struct jabber_buddy *bud, *new, *bi;
-	char *s;
-	
-	if( !( s = strchr( full_jid, '/' ) ) )
-		return NULL;
+	char *s, *full_jid;
+	
+	full_jid = jabber_normalize( full_jid_ );
+	
+	if( ( s = strchr( full_jid, '/' ) ) )
+		*s = 0;
 	
 	new = g_new0( struct jabber_buddy, 1 );
 	
-	*s = 0;
 	if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) )
 	{
-		new->handle = bud->handle;
+		/* If this is a transport buddy or whatever, it can't have more
+		   than one instance, so this is always wrong: */
+		if( s == NULL || bud->resource == NULL )
+		{
+			if( s ) *s = '/';
+			g_free( new );
+			g_free( full_jid );
+			return NULL;
+		}
+		
+		new->bare_jid = bud->bare_jid;
 		
 		/* We already have another resource for this buddy, add the
@@ -273,9 +302,10 @@
 		for( bi = bud; bi; bi = bi->next )
 		{
-			/* Check for dupes. Resource seem to be case sensitive. */
-			if( strcmp( bi->resource, s + 1 ) == 0 )
+			/* Check for dupes. */
+			if( g_strcasecmp( bi->resource, s + 1 ) == 0 )
 			{
 				*s = '/';
 				g_free( new );
+				g_free( full_jid );
 				return NULL;
 			}
@@ -290,11 +320,20 @@
 	else
 	{
-		new->handle = g_strdup( full_jid );
-		g_hash_table_insert( jd->buddies, new->handle, new );
-	}
-	
-	*s = '/';
-	new->full_jid = g_strdup( full_jid );
-	new->resource = strchr( new->full_jid, '/' ) + 1;
+		new->bare_jid = g_strdup( full_jid );
+		g_hash_table_insert( jd->buddies, new->bare_jid, new );
+	}
+	
+	if( s )
+	{
+		*s = '/';
+		new->full_jid = full_jid;
+		new->resource = strchr( new->full_jid, '/' ) + 1;
+	}
+	else
+	{
+		/* Let's waste some more bytes of RAM instead of to make
+		   memory management a total disaster here.. */
+		new->full_jid = full_jid;
+	}
 	
 	return new;
@@ -304,9 +343,11 @@
    asked for a bare JID, it uses the "resource_select" setting to see which
    resource to pick. */
-struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid )
+struct jabber_buddy *jabber_buddy_by_jid( struct gaim_connection *gc, char *jid_, get_buddy_flags_t flags )
 {
 	struct jabber_data *jd = gc->proto_data;
 	struct jabber_buddy *bud;
-	char *s;
+	char *s, *jid;
+	
+	jid = jabber_normalize( jid_ );
 	
 	if( ( s = strchr( jid, '/' ) ) )
@@ -314,7 +355,25 @@
 		*s = 0;
 		if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) )
-			for( ; bud; bud = bud->next )
-				if( strcmp( bud->resource, s + 1 ) == 0 )
-					break;
+		{
+			/* Is this one of those no-resource buddies? */
+			if( bud->resource == NULL )
+			{
+				bud = NULL;
+			}
+			else
+			{
+				/* See if there's an exact match. */
+				for( ; bud; bud = bud->next )
+					if( g_strcasecmp( bud->resource, s + 1 ) == 0 )
+						break;
+			}
+		}
+		
+		*s = '/';
+		if( bud == NULL && ( flags & GET_BUDDY_CREAT ) )
+			bud = jabber_buddy_add( gc, jid );
+		
+		g_free( jid );
+		return bud;
 	}
 	else
@@ -323,5 +382,15 @@
 		char *set;
 		
-		best_prio = best_time = bud = g_hash_table_lookup( jd->buddies, jid );
+		bud = g_hash_table_lookup( jd->buddies, jid );
+		
+		g_free( jid );
+		
+		/* An exact match, or only one option. */
+		if( bud == NULL )
+			return ( flags & GET_BUDDY_CREAT ) ? jabber_buddy_add( gc, jid ) : NULL;
+		else if( ( bud->resource == NULL || bud->next == NULL ) )
+			return bud;
+		
+		best_prio = best_time = bud;
 		for( ; bud; bud = bud->next )
 		{
@@ -339,21 +408,20 @@
 			return best_prio;
 	}
-	
-	*s = '/';
-	return bud;
 }
 
 /* Remove one specific full JID from our list. Use this when a buddy goes
-   off-line (because (s)he can still be online from a different location. */
-int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid )
+   off-line (because (s)he can still be online from a different location.
+   XXX: See above, we should accept bare JIDs too... */
+int jabber_buddy_remove( struct gaim_connection *gc, char *full_jid_ )
 {
 	struct jabber_data *jd = gc->proto_data;
 	struct jabber_buddy *bud, *prev, *bi;
-	char *s;
-	
-	if( !( s = strchr( full_jid, '/' ) ) )
-		return 0;
-	
-	*s = 0;
+	char *s, *full_jid;
+	
+	full_jid = jabber_normalize( full_jid_ );
+	
+	if( ( s = strchr( full_jid, '/' ) ) )
+		*s = 0;
+	
 	if( ( bud = g_hash_table_lookup( jd->buddies, full_jid ) ) )
 	{
@@ -361,17 +429,30 @@
 		   matches), removing it is simple. (And the hash reference
 		   should be removed too!) */
-		if( bud->next == NULL && strcmp( bud->resource, s + 1 ) == 0 )
-		{
-			g_hash_table_remove( jd->buddies, bud->handle );
-			g_free( bud->handle );
+		if( bud->next == NULL && ( ( s == NULL || bud->resource == NULL ) || g_strcasecmp( bud->resource, s + 1 ) == 0 ) )
+		{
+			g_hash_table_remove( jd->buddies, bud->bare_jid );
+			g_free( bud->bare_jid );
 			g_free( bud->full_jid );
 			g_free( bud->away_message );
 			g_free( bud );
+			
+			g_free( full_jid );
+			
+			return 1;
+		}
+		else if( s == NULL || bud->resource == NULL )
+		{
+			/* Tried to remove a bare JID while this JID does seem
+			   to have resources... (Or the opposite.) *sigh* */
+			g_free( full_jid );
+			return 0;
 		}
 		else
 		{
 			for( bi = bud, prev = NULL; bi; bi = (prev=bi)->next )
-				if( strcmp( bi->resource, s + 1 ) == 0 )
+				if( g_strcasecmp( bi->resource, s + 1 ) == 0 )
 					break;
+			
+			g_free( full_jid );
 			
 			if( bi )
@@ -382,23 +463,21 @@
 					/* The hash table should point at the second
 					   item, because we're removing the first. */
-					g_hash_table_replace( jd->buddies, bi->handle, bi->next );
+					g_hash_table_replace( jd->buddies, bi->bare_jid, bi->next );
 				
 				g_free( bi->full_jid );
 				g_free( bi->away_message );
 				g_free( bi );
+				
+				return 1;
 			}
 			else
 			{
-				*s = '/';
 				return 0;
 			}
 		}
-		
-		*s = '/';
-		return 1;
-	}
-	else
-	{
-		*s = '/';
+	}
+	else
+	{
+		g_free( full_jid );
 		return 0;
 	}
@@ -408,11 +487,14 @@
    specified bare JID. Use this when removing someone from the contact
    list, for example. */
-int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid )
+int jabber_buddy_remove_bare( struct gaim_connection *gc, char *bare_jid_ )
 {
 	struct jabber_data *jd = gc->proto_data;
 	struct jabber_buddy *bud, *next;
-	
-	if( strchr( bare_jid, '/' ) )
+	char *bare_jid;
+	
+	if( strchr( bare_jid_, '/' ) )
 		return 0;
+	
+	bare_jid = jabber_normalize( bare_jid_ );
 	
 	if( ( bud = g_hash_table_lookup( jd->buddies, bare_jid ) ) )
@@ -420,5 +502,5 @@
 		/* Most important: Remove the hash reference. We don't know
 		   this buddy anymore. */
-		g_hash_table_remove( jd->buddies, bud->handle );
+		g_hash_table_remove( jd->buddies, bud->bare_jid );
 		
 		/* Deallocate the linked list of resources. */
@@ -432,8 +514,10 @@
 		}
 		
+		g_free( bare_jid );
 		return 1;
 	}
 	else
 	{
+		g_free( bare_jid );
 		return 0;
 	}
Index: protocols/jabber/message.c
===================================================================
--- protocols/jabber/message.c	(revision 47d3ac46306965e9db66096eef8c60c8e7985950)
+++ protocols/jabber/message.c	(revision 0d3f30f5449cf1730c006314f3dd60843e911ad1)
@@ -47,5 +47,5 @@
 		if( ( s = strchr( from, '/' ) ) )
 		{
-			if( ( bud = jabber_buddy_by_jid( gc, from ) ) )
+			if( ( bud = jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT ) ) )
 				bud->last_act = time( NULL );
 			else
@@ -76,5 +76,5 @@
 		
 		if( fullmsg->len > 0 )
-			serv_got_im( gc, bud ? bud->handle : from, fullmsg->str, 0, 0, fullmsg->len );
+			serv_got_im( gc, bud ? bud->bare_jid : from, fullmsg->str, 0, 0, fullmsg->len );
 		
 		g_string_free( fullmsg, TRUE );
@@ -84,5 +84,5 @@
 		{
 			bud->flags |= JBFLAG_DOES_XEP85;
-			serv_got_typing( gc, bud ? bud->handle : from, 0, 1 );
+			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 1 );
 		}
 		/* No need to send a "stopped typing" signal when there's a message. */
@@ -90,10 +90,10 @@
 		{
 			bud->flags |= JBFLAG_DOES_XEP85;
-			serv_got_typing( gc, bud ? bud->handle : from, 0, 0 );
+			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 0 );
 		}
 		else if( xt_find_node( node->children, "paused" ) )
 		{
 			bud->flags |= JBFLAG_DOES_XEP85;
-			serv_got_typing( gc, bud ? bud->handle : from, 0, 2 );
+			serv_got_typing( gc, bud ? bud->bare_jid : from, 0, 2 );
 		}
 		
Index: protocols/jabber/presence.c
===================================================================
--- protocols/jabber/presence.c	(revision 47d3ac46306965e9db66096eef8c60c8e7985950)
+++ protocols/jabber/presence.c	(revision 0d3f30f5449cf1730c006314f3dd60843e911ad1)
@@ -38,32 +38,8 @@
 	if( type == NULL )
 	{
-		if( ( s = strchr( from, '/' ) ) == NULL )
+		if( !( bud = jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )
 		{
-			char *s = xt_to_string( node );
-			serv_got_crap( gc, "WARNING: Ignoring presence tag with bare JID: %s", s );
-			g_free( s );
+			serv_got_crap( gc, "WARNING: Could not handle presence information from JID: %s", from );
 			return XT_HANDLED;
-		}
-		
-		if( !( bud = jabber_buddy_by_jid( gc, from ) ) )
-		{
-			/* FOR NOW, s still contains the location of the /.
-			   Keep this in mind when changing things here. :-) */
-			
-			/* We check if the buddy is in the contact list,
-			   because Jabber servers seem to like to send
-			   presence information of buddies we removed
-			   from our list sometimes, for example... */
-			
-			*s = 0;
-			if( find_buddy( gc, from ) == NULL )
-			{
-				*s = '/';
-				serv_got_crap( gc, "WARNING: Ignoring presence information from unknown JID: %s", from );
-				return XT_HANDLED;
-			}
-			*s = '/';
-			
-			bud = jabber_buddy_add( gc, from );
 		}
 		
@@ -89,20 +65,10 @@
 			bud->priority = 0;
 		
-		serv_got_update( gc, bud->handle, 1, 0, 0, 0,
+		serv_got_update( gc, bud->bare_jid, 1, 0, 0, 0,
 		                 bud->away_state ? UC_UNAVAILABLE : 0, 0 );
 	}
 	else if( strcmp( type, "unavailable" ) == 0 )
 	{
-		char *s;
-		
-		if( ( s = strchr( from, '/' ) ) == NULL )
-		{
-			char *s = xt_to_string( node );
-			serv_got_crap( gc, "WARNING: Ignoring presence tag with bare JID: %s\n", s );
-			g_free( s );
-			return XT_HANDLED;
-		}
-		
-		if( jabber_buddy_by_jid( gc, from ) == NULL )
+		if( jabber_buddy_by_jid( gc, from, GET_BUDDY_EXACT ) == NULL )
 		{
 			serv_got_crap( gc, "WARNING: Received presence information from unknown JID: %s", from );
@@ -111,12 +77,20 @@
 		
 		jabber_buddy_remove( gc, from );
-		*s = 0;
 		
-		/* Only count this as offline if there's no other resource
-		   available anymore. */
-		if( jabber_buddy_by_jid( gc, from ) == NULL )
+		if( ( s = strchr( from, '/' ) ) )
+		{
+			*s = 0;
+		
+			/* Only count this as offline if there's no other resource
+			   available anymore. */
+			if( jabber_buddy_by_jid( gc, from, 0 ) == NULL )
+				serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 );
+			
+			*s = '/';
+		}
+		else
+		{
 			serv_got_update( gc, from, 0, 0, 0, 0, 0, 0 );
-		
-		*s = '/';
+		}
 	}
 	else if( strcmp( type, "subscribe" ) == 0 )
@@ -126,4 +100,5 @@
 	else if( strcmp( type, "subscribed" ) == 0 )
 	{
+		/* Not sure about this one, actually... */
 		serv_got_crap( gc, "%s just accepted your authorization request", from );
 	}
