Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/jabber/jabber.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -33,13 +33,31 @@
 #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;
-	
-	s = set_add( &acc->set, "port", JABBER_PORT_DEFAULT, set_eval_int, acc );
+	char str[16];
+	
+	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;
 	
@@ -74,4 +92,5 @@
 	struct ns_srv_reply *srv = NULL;
 	char *connect_to, *s;
+	int i;
 	
 	/* For now this is needed in the _connected() handlers if using
@@ -179,9 +198,11 @@
 	imcb_log( ic, "Connecting" );
 	
-	if( set_getint( &acc->set, "port" ) < JABBER_PORT_MIN ||
-	    set_getint( &acc->set, "port" ) > JABBER_PORT_MAX )
-	{
-		imcb_log( ic, "Incorrect port number, must be in the %d-%d range",
-		               JABBER_PORT_MIN, 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, "Illegal port number" );
 		imc_logout( ic, FALSE );
 		return;
@@ -221,22 +242,18 @@
 }
 
+/* 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 );
 }
 
@@ -281,5 +298,4 @@
 	xt_free( jd->xt );
 	
-	g_free( jd->cached_id_prefix );
 	g_free( jd->away_message );
 	g_free( jd->username );
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/jabber/jabber.h	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -94,5 +94,5 @@
 	char *away_message;
 	
-	char *cached_id_prefix;
+	md5_state_t cached_id_prefix;
 	GHashTable *node_cache;
 	GHashTable *buddies;
@@ -177,8 +177,4 @@
 
 #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
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/jabber/jabber_util.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -23,4 +23,6 @@
 
 #include "jabber.h"
+#include "md5.h"
+#include "base64.h"
 
 static unsigned int next_id = 1;
@@ -138,9 +140,19 @@
 	struct jabber_data *jd = ic->proto_data;
 	struct jabber_cache_entry *entry = g_new0( struct jabber_cache_entry, 1 );
-	char *id;
-	
-	id = g_strdup_printf( "%s%05x", jd->cached_id_prefix, ( next_id++ ) & 0xfffff );
+	md5_state_t id_hash;
+	md5_byte_t id_sum[16];
+	char *id, *asc_hash;
+	
+	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;
@@ -188,5 +200,5 @@
 	
 	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
@@ -200,6 +212,12 @@
 	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 )
@@ -294,12 +312,10 @@
 	len = strlen( orig );
 	new = g_new( char, len + 1 );
-	for( i = 0; i < len; i ++ )
-	{
-		/* don't normalize the resource */
-		if( orig[i] == '/' )
-			break;
+	
+	/* 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( ; i < len; i ++ )
+	for( ; orig[i]; i ++ )
 		new[i] = orig[i];
 	
@@ -345,5 +361,5 @@
 		{
 			/* Check for dupes. */
-			if( g_strcasecmp( bi->resource, s + 1 ) == 0 )
+			if( strcmp( bi->resource, s + 1 ) == 0 )
 			{
 				*s = '/';
@@ -398,5 +414,5 @@
 	if( ( s = strchr( jid, '/' ) ) )
 	{
-		int none_found = 0;
+		int bare_exists = 0;
 		
 		*s = 0;
@@ -421,19 +437,17 @@
 			/* 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... */
-		}
-		
-		if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) )
+			/* 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 ) &&
+		    ( !bare_exists || imcb_find_buddy( ic, jid ) ) )
 		{
 			*s = '/';
@@ -460,5 +474,5 @@
 			/* 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;
@@ -536,5 +550,7 @@
 		   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 );
@@ -559,5 +575,5 @@
 		{
 			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;
 			
Index: protocols/jabber/message.c
===================================================================
--- protocols/jabber/message.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/jabber/message.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -49,4 +49,21 @@
 	{
 		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, '/' ) ) )
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/msn/ns.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -278,9 +278,23 @@
 		if( num_parts == 5 )
 		{
+			int i, groupcount;
+			
+			groupcount = atoi( cmd[4] );
+			if( groupcount > 0 )
+			{
+				/* valgrind says this is leaking memory, I'm guessing
+				   that this happens during server redirects. */
+				if( md->grouplist )
+				{
+					for( i = 0; i < md->groupcount; i ++ )
+						g_free( md->grouplist[i] );
+					g_free( md->grouplist );
+				}
+				
+				md->groupcount = groupcount;
+				md->grouplist = g_new0( char *, md->groupcount );
+			}
+			
 			md->buddycount = atoi( cmd[3] );
-			md->groupcount = atoi( cmd[4] );
-			if( md->groupcount > 0 )
-				md->grouplist = g_new0( char *, md->groupcount );
-			
 			if( !*cmd[3] || md->buddycount == 0 )
 				msn_logged_in( ic );
@@ -665,4 +679,7 @@
 					imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders );
 				}
+				
+				g_free( inbox );
+				g_free( folders );
 			}
 			else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 )
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/nogaim.h	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -45,9 +45,4 @@
 #include "md5.h"
 #include "ft.h"
-
-#define BUF_LEN MSG_LEN
-#define BUF_LONG ( BUF_LEN * 2 )
-#define MSG_LEN 2048
-#define BUF_LEN MSG_LEN
 
 #define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/oscar/oscar.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -60,4 +60,7 @@
 
 #define OSCAR_GROUP "Friends"
+
+#define BUF_LEN 2048
+#define BUF_LONG ( BUF_LEN * 2 )
 
 /* Don't know if support for UTF8 is really working. For now it's UTF16 here.
@@ -240,4 +243,30 @@
 };
 static int msgerrreasonlen = 25;
+
+/* Hurray, this function is NOT thread-safe \o/ */
+static char *normalize(const char *s)
+{
+	static char buf[BUF_LEN];
+	char *t, *u;
+	int x = 0;
+
+	g_return_val_if_fail((s != NULL), NULL);
+
+	u = t = g_strdup(s);
+
+	strcpy(t, s);
+	g_strdown(t);
+
+	while (*t && (x < BUF_LEN - 1)) {
+		if (*t != ' ' && *t != '!') {
+			buf[x] = *t;
+			x++;
+		}
+		t++;
+	}
+	buf[x] = '\0';
+	g_free(u);
+	return buf;
+}
 
 static gboolean oscar_callback(gpointer data, gint source,
@@ -1002,11 +1031,11 @@
 	}
 
-	tmp = g_strdup(normalize(ic->acc->user));
-	if (!strcmp(tmp, normalize(info->sn)))
+	if (!aim_sncmp(ic->acc->user, info->sn))
 		g_snprintf(ic->displayname, sizeof(ic->displayname), "%s", info->sn);
-	g_free(tmp);
-
-	imcb_buddy_status(ic, info->sn, flags, state_string, NULL);
-	/* imcb_buddy_times(ic, info->sn, signon, time_idle); */
+
+	tmp = normalize(info->sn);
+	imcb_buddy_status(ic, tmp, flags, state_string, NULL);
+	/* imcb_buddy_times(ic, tmp, signon, time_idle); */
+
 
 	return 1;
@@ -1022,5 +1051,5 @@
 	va_end(ap);
 
-	imcb_buddy_status(ic, info->sn, 0, NULL, NULL );
+	imcb_buddy_status(ic, normalize(info->sn), 0, NULL, NULL );
 
 	return 1;
@@ -1078,5 +1107,5 @@
 	
 	strip_linefeed(tmp);
-	imcb_buddy_msg(ic, userinfo->sn, tmp, flags, 0);
+	imcb_buddy_msg(ic, normalize(userinfo->sn), tmp, flags, 0);
 	g_free(tmp);
 	
@@ -1177,5 +1206,5 @@
 			message = g_strdup(args->msg);
 			strip_linefeed(message);
-			imcb_buddy_msg(ic, uin, message, 0, 0);
+			imcb_buddy_msg(ic, normalize(uin), message, 0, 0);
 			g_free(uin);
 			g_free(message);
@@ -1196,5 +1225,5 @@
 
 			strip_linefeed(message);
-			imcb_buddy_msg(ic, uin, message, 0, 0);
+			imcb_buddy_msg(ic, normalize(uin), message, 0, 0);
 			g_free(uin);
 			g_free(m);
@@ -1471,5 +1500,5 @@
 
 	for (i = 0; i < count; i++)
-		imcb_chat_add_buddy(c->cnv, info[i].sn);
+		imcb_chat_add_buddy(c->cnv, normalize(info[i].sn));
 
 	return 1;
@@ -1494,5 +1523,5 @@
 
 	for (i = 0; i < count; i++)
-		imcb_chat_remove_buddy(c->cnv, info[i].sn, NULL);
+		imcb_chat_remove_buddy(c->cnv, normalize(info[i].sn), NULL);
 
 	return 1;
@@ -1545,5 +1574,5 @@
 	tmp = g_malloc(BUF_LONG);
 	g_snprintf(tmp, BUF_LONG, "%s", msg);
-	imcb_chat_msg(ccon->cnv, info->sn, tmp, 0, 0);
+	imcb_chat_msg(ccon->cnv, normalize(info->sn), tmp, 0, 0);
 	g_free(tmp);
 
@@ -1758,5 +1787,5 @@
 			g_snprintf(sender, sizeof(sender), "%u", msg->sender);
 			strip_linefeed(dialog_msg);
-			imcb_buddy_msg(ic, sender, dialog_msg, 0, t);
+			imcb_buddy_msg(ic, normalize(sender), dialog_msg, 0, t);
 			g_free(dialog_msg);
 		} break;
@@ -1779,5 +1808,5 @@
 
 			strip_linefeed(dialog_msg);
-			imcb_buddy_msg(ic, sender, dialog_msg, 0, t);
+			imcb_buddy_msg(ic, normalize(sender), dialog_msg, 0, t);
 			g_free(dialog_msg);
 			g_free(m);
@@ -2017,11 +2046,14 @@
 	struct aim_ssi_item *curitem;
 	int tmp;
+	char *nrm;
 
 	/* Add from server list to local list */
 	tmp = 0;
 	for (curitem=sess->ssi.items; curitem; curitem=curitem->next) {
+		nrm = curitem->name ? normalize(curitem->name) : NULL;
+		
 		switch (curitem->type) {
 			case 0x0000: /* Buddy */
-				if ((curitem->name) && (!imcb_find_buddy(ic, curitem->name))) {
+				if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
 					char *realname = NULL;
 
@@ -2029,9 +2061,9 @@
 						    realname = aim_gettlv_str(curitem->data, 0x0131, 1);
 						
-					imcb_add_buddy(ic, curitem->name, NULL);
+					imcb_add_buddy(ic, nrm, NULL);
 					
 					if (realname) {
-						imcb_buddy_nick_hint(ic, curitem->name, realname);
-						imcb_rename_buddy(ic, curitem->name, realname);
+						imcb_buddy_nick_hint(ic, nrm, realname);
+						imcb_rename_buddy(ic, nrm, realname);
 						g_free(realname);
 					}
@@ -2045,5 +2077,5 @@
 					if (!list) {
 						char *name;
-						name = g_strdup(normalize(curitem->name));
+						name = g_strdup(nrm);
 						ic->permit = g_slist_append(ic->permit, name);
 						tmp++;
@@ -2058,5 +2090,5 @@
 					if (!list) {
 						char *name;
-						name = g_strdup(normalize(curitem->name));
+						name = g_strdup(nrm);
 						ic->deny = g_slist_append(ic->deny, name);
 						tmp++;
@@ -2120,5 +2152,5 @@
 			if( st == 0x00 )
 			{
-				imcb_add_buddy( sess->aux_data, list, NULL );
+				imcb_add_buddy( sess->aux_data, normalize(list), NULL );
 			}
 			else if( st == 0x0E )
@@ -2450,13 +2482,13 @@
 	if(type2 == 0x0002) {
 		/* User is typing */
-		imcb_buddy_typing(ic, sn, OPT_TYPING);
+		imcb_buddy_typing(ic, normalize(sn), OPT_TYPING);
 	} 
 	else if (type2 == 0x0001) {
 		/* User has typed something, but is not actively typing (stale) */
-		imcb_buddy_typing(ic, sn, OPT_THINKING);
+		imcb_buddy_typing(ic, normalize(sn), OPT_THINKING);
 	}
 	else {
 		/* User has stopped typing */
-		imcb_buddy_typing(ic, sn, 0);
+		imcb_buddy_typing(ic, normalize(sn), 0);
 	}
 	
Index: protocols/yahoo/libyahoo2.c
===================================================================
--- protocols/yahoo/libyahoo2.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/yahoo/libyahoo2.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -69,6 +69,4 @@
 #ifdef __MINGW32__
 # include <winsock2.h>
-# define write(a,b,c) send(a,b,c,0)
-# define read(a,b,c)  recv(a,b,c,0)
 #endif
 
@@ -381,5 +379,4 @@
 
 /* call repeatedly to get the next one */
-/*
 static struct yahoo_input_data * find_input_by_id(int id)
 {
@@ -392,5 +389,4 @@
 	return NULL;
 }
-*/
 
 static struct yahoo_input_data * find_input_by_id_and_webcam_user(int id, const char * who)
@@ -797,4 +793,5 @@
 {
 	struct yahoo_data *yd = find_conn_by_id(id);
+	
 	if(!yd)
 		return;
@@ -3166,5 +3163,5 @@
 
 	LOG(("write callback: id=%d fd=%d data=%p", id, fd, data));
-	if(!yid || !yid->txqueues)
+	if(!yid || !yid->txqueues || !find_conn_by_id(id))
 		return -2;
 	
@@ -3842,9 +3839,7 @@
 	}
 
-	
-/*	do {
+	do {
 		yahoo_input_close(yid);
-	} while((yid = find_input_by_id(id)));*/
-	
+	} while((yid = find_input_by_id(id)));
 }
 
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/yahoo/yahoo.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -163,8 +163,5 @@
 	g_slist_free( yd->buddygroups );
 	
-	if( yd->logged_in )
-		yahoo_logoff( yd->y2_id );
-	else
-		yahoo_close( yd->y2_id );
+	yahoo_logoff( yd->y2_id );
 	
 	g_free( yd );
@@ -454,8 +451,4 @@
 	struct byahoo_write_ready_data *d = data;
 	
-	if( !byahoo_get_ic_by_id( d->id ) )
-		/* WTF doesn't libyahoo clean this up? */
-		return FALSE;
-	
 	yahoo_write_ready( d->id, d->fd, d->data );
 	
@@ -672,7 +665,4 @@
 	
 	imcb_error( ic, "%s", err );
-	
-	if( fatal )
-		imc_logout( ic, TRUE );
 }
 
Index: protocols/yahoo/yahoo_httplib.c
===================================================================
--- protocols/yahoo/yahoo_httplib.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/yahoo/yahoo_httplib.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -51,6 +51,4 @@
 #ifdef __MINGW32__
 # include <winsock2.h>
-# define write(a,b,c) send(a,b,c,0)
-# define read(a,b,c)  recv(a,b,c,0)
 # define snprintf _snprintf
 #endif
