Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision 764b163d6bc0587498c14de8023d70aea076e646)
+++ protocols/nogaim.c	(revision ebb95b68792dde490a1ea1042209525f176af58d)
@@ -99,5 +99,4 @@
 }
 
- 
 struct prpl *find_protocol(const char *name)
 {
@@ -289,5 +288,5 @@
 {
 	irc_t *irc = ic->irc;
-	user_t *t, *u = irc->users;
+	user_t *t, *u;
 	account_t *a;
 	
@@ -306,4 +305,5 @@
 	b_event_remove( ic->inpa );
 	
+	u = irc->users;
 	while( u )
 	{
@@ -428,5 +428,4 @@
 {
 	user_t *u = user_findhandle( ic, handle );
-	char *s, newnick[MAX_NICK_LENGTH+1];
 	
 	if( !u || !realname ) return;
@@ -440,28 +439,51 @@
 		if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) )
 			imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );
-		
-		if( !u->online && !nick_saved( ic->acc, handle ) )
-		{
-			/* Detect numeric handles: */
-			for( s = u->user; isdigit( *s ); s++ );
+	}
+}
+
+void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group )
+{
+	user_t *u;
+	
+	if( ( u = user_findhandle( ic, handle ) ) )
+		user_del( ic->irc, u->nick );
+}
+
+/* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM
+   modules to suggest a nickname for a handle. */
+void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick )
+{
+	user_t *u = user_findhandle( ic, handle );
+	char newnick[MAX_NICK_LENGTH+1], *orig_nick;
+	
+	if( u && !u->online && !nick_saved( ic->acc, handle ) )
+	{
+		/* Only do this if the person isn't online yet (which should
+		   be the case if we just added it) and if the user hasn't
+		   assigned a nickname to this buddy already. */
+		
+		strncpy( newnick, nick, MAX_NICK_LENGTH );
+		newnick[MAX_NICK_LENGTH] = 0;
+		
+		/* Some processing to make sure this string is a valid IRC nickname. */
+		nick_strip( newnick );
+		if( set_getbool( &ic->irc->set, "lcnicks" ) )
+			nick_lc( newnick );
+		
+		if( strcmp( u->nick, newnick ) != 0 )
+		{
+			/* Only do this if newnick is different from the current one.
+			   If rejoining a channel, maybe we got this nick already
+			   (and dedupe would only add an underscore. */
+			nick_dedupe( ic->acc, handle, newnick );
 			
-			if( *s == 0 )
-			{
-				/* If we reached the end of the string, it only contained numbers.
-				   Seems to be an ICQ# then, so hopefully realname contains
-				   something more useful. */
-				strcpy( newnick, realname );
-				
-				/* Some processing to make sure this string is a valid IRC nickname. */
-				nick_strip( newnick );
-				if( set_getbool( &ic->irc->set, "lcnicks" ) )
-					nick_lc( newnick );
-				
-				u->nick = g_strdup( newnick );
-			}
-		}
-	}
-}
-
+			/* u->nick will be freed halfway the process, so it can't be
+			   passed as an argument. */
+			orig_nick = g_strdup( u->nick );
+			user_rename( ic->irc, orig_nick, newnick );
+			g_free( orig_nick );
+		}
+	}
+}
 
 /* prpl.c */
@@ -554,6 +576,6 @@
 		u->online = 0;
 		
-		/* Remove him/her from the conversations to prevent PART messages after he/she QUIT already */
-		for( c = ic->conversations; c; c = c->next )
+		/* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */
+		for( c = ic->groupchats; c; c = c->next )
 			remove_chat_buddy_silent( c, handle );
 	}
@@ -670,8 +692,8 @@
 }
 
-void imcb_chat_removed( struct groupchat *c )
+void imcb_chat_free( struct groupchat *c )
 {
 	struct im_connection *ic = c->ic;
-	struct groupchat *l = NULL;
+	struct groupchat *l;
 	GList *ir;
 	
@@ -693,8 +715,11 @@
 		}
 		
+		/* Find the previous chat in the linked list. */
+		for( l = ic->groupchats; l && l->next != c; l = l->next );
+		
 		if( l )
 			l->next = c->next;
 		else
-			ic->conversations = c->next;
+			ic->groupchats = c->next;
 		
 		for( ir = c->in_room; ir; ir = ir->next )
@@ -741,11 +766,11 @@
 	/* This one just creates the conversation structure, user won't see anything yet */
 	
-	if( ic->conversations )
-	{
-		for( c = ic->conversations; c->next; c = c->next );
+	if( ic->groupchats )
+	{
+		for( c = ic->groupchats; c->next; c = c->next );
 		c = c->next = g_new0( struct groupchat, 1 );
 	}
 	else
-		ic->conversations = c = g_new0( struct groupchat, 1 );
+		ic->groupchats = c = g_new0( struct groupchat, 1 );
 	
 	c->ic = ic;
@@ -796,4 +821,5 @@
 }
 
+/* This function is one BIG hack... :-( EREWRITE */
 void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason )
 {
@@ -807,4 +833,7 @@
 	if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )
 	{
+		if( b->joined == 0 )
+			return;
+		
 		u = user_find( b->ic->irc, b->ic->irc->nick );
 		b->joined = 0;
@@ -816,7 +845,6 @@
 	}
 	
-	if( remove_chat_buddy_silent( b, handle ) )
-		if( ( b->joined || me ) && u )
-			irc_part( b->ic->irc, u, b->channel );
+	if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
+		irc_part( b->ic->irc, u, b->channel );
 }
 
@@ -844,22 +872,4 @@
 
 /* Misc. BitlBee stuff which shouldn't really be here */
-
-struct groupchat *chat_by_channel( char *channel )
-{
-	struct im_connection *ic;
-	struct groupchat *c;
-	GSList *l;
-	
-	/* This finds the connection which has a conversation which belongs to this channel */
-	for( l = connections; l; l = l->next )
-	{
-		ic = l->data;
-		for( c = ic->conversations; c && g_strcasecmp( c->channel, channel ) != 0; c = c->next );
-		if( c )
-			return c;
-	}
-	
-	return NULL;
-}
 
 char *set_eval_away_devoice( set_t *set, char *value )
@@ -1095,2 +1105,34 @@
 	ic->acc->prpl->rem_deny( ic, handle );
 }
+
+void imcb_clean_handle( struct im_connection *ic, char *handle )
+{
+	/* Accepts a handle and does whatever is necessary to make it
+	   BitlBee-friendly. Currently this means removing everything
+	   outside 33-127 (ASCII printable excl spaces), @ (only one
+	   is allowed) and ! and : */
+	char out[strlen(handle)+1];
+	int s, d;
+	
+	s = d = 0;
+	while( handle[s] )
+	{
+		if( handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' &&
+		    ( handle[s] & 0x80 ) == 0 )
+		{
+			if( handle[s] == '@' )
+			{
+				/* See if we got an @ already? */
+				out[d] = 0;
+				if( strchr( out, '@' ) )
+					continue;
+			}
+			
+			out[d++] = handle[s];
+		}
+		s ++;
+	}
+	out[d] = handle[s];
+	
+	strcpy( handle, out );
+}
